---
name: svelte
description: Svelte 5 - Reactive UI framework with compiler magic, Runes API, SvelteKit full-stack framework, SSR/SSG, minimal JavaScript
version: 1.0.0
category: toolchain
author: Claude MPM Team
license: MIT
progressive_disclosure:
entry_point:
summary: "Compiler-first reactive UI: $state/$derived/$effect Runes, SvelteKit SSR/SSG, minimal bundle, write less code"
when_to_use: "Interactive UIs, dashboards, SPAs, static sites, full-stack apps with performance focus and developer ergonomics"
quick_start: "1. npm create svelte@latest 2. Use $state() for reactive state 3. Use $derived() for computed 4. Deploy with adapters"
context_limit: 85
tags:
- svelte
- svelte5
- sveltekit
- runes
- reactivity
- ssr
- ssg
- compiler
- performance
- frontend
requires_tools: []
---
# Svelte 5 - Compiler-First Reactive Framework
## Overview
Svelte is a **compiler-based** reactive UI framework that shifts work from runtime to build time. Unlike React/Vue, Svelte compiles components to highly optimized vanilla JavaScript with minimal overhead. **Svelte 5** introduces Runes API for explicit, fine-grained reactivity.
**Key Features**:
- **Runes API**: $state, $derived, $effect for explicit reactivity
- **Zero runtime overhead**: Compiles to vanilla JS
- **Built-in state management**: No external libraries needed
- **SvelteKit**: Full-stack framework with SSR/SSG/SPA
- **Write less code**: Simple, readable component syntax
- **Exceptional performance**: Small bundles, fast runtime
**Installation**:
```bash
# Create new SvelteKit project
npm create svelte@latest my-app
cd my-app
npm install
npm run dev
# Or Svelte only (no SvelteKit)
npm create vite@latest my-app -- --template svelte-ts
```
## Svelte 5 Runes API (Modern Approach)
### State Management with $state
```svelte
```
### Computed Values with $derived
```svelte
{greeting}
Average: {average.toFixed(2)}
```
### Side Effects with $effect
```svelte
```
### Component Props with $props
```svelte
{displayTitle}
Count: {count}
```
### Two-Way Binding with $bindable
```svelte
Found {results.length} results for "{query}"
```
## Component Patterns
### Basic Component Structure
```svelte
Count: {count} (Doubled: {doubled})
```
### Conditional Rendering
```svelte
{#if loading}
Loading...
{:else if loggedIn && user}
Welcome, {user.name}!
{:else}
Please log in
{/if}
```
### Lists and Keyed Each Blocks
```svelte
```
## SvelteKit Framework
### Project Structure
```
my-app/
├── src/
│ ├── routes/
│ │ ├── +page.svelte # Home page
│ │ ├── +page.ts # Universal load
│ │ ├── +page.server.ts # Server load
│ │ ├── +layout.svelte # Shared layout
│ │ ├── about/
│ │ │ └── +page.svelte # /about
│ │ └── blog/
│ │ ├── +page.svelte # /blog
│ │ └── [slug]/
│ │ └── +page.svelte # /blog/my-post
│ ├── lib/
│ │ ├── components/
│ │ ├── stores/
│ │ └── utils/
│ └── app.html
├── static/ # Static assets
└── svelte.config.js
```
### Load Functions (Data Fetching)
```typescript
// src/routes/blog/[slug]/+page.ts
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params, fetch }) => {
const response = await fetch(`/api/posts/${params.slug}`);
const post = await response.json();
return {
post
};
};
```
```svelte
{data.post.title}
{@html data.post.content}
```
### Server-Only Load Functions
```typescript
// src/routes/admin/+page.server.ts
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ locals }) => {
if (!locals.user?.isAdmin) {
throw redirect(303, '/login');
}
const users = await db.users.findMany();
return {
users
};
};
```
### Form Actions
```typescript
// src/routes/login/+page.server.ts
import { fail, redirect } from '@sveltejs/kit';
import type { Actions } from './$types';
import { z } from 'zod';
const schema = z.object({
email: z.string().email(),
password: z.string().min(8)
});
export const actions = {
default: async ({ request, cookies }) => {
const formData = await request.formData();
const data = Object.fromEntries(formData);
const result = schema.safeParse(data);
if (!result.success) {
return fail(400, {
errors: result.error.flatten().fieldErrors
});
}
const user = await authenticateUser(result.data);
if (!user) {
return fail(401, { message: 'Invalid credentials' });
}
cookies.set('session', user.sessionToken, { path: '/' });
throw redirect(303, '/dashboard');
}
} satisfies Actions;
```
```svelte
```
## State Management Patterns
### Runes-Based Store (Modern)
```typescript
// src/lib/stores/cart.svelte.ts
interface CartItem {
id: number;
name: string;
price: number;
quantity: number;
}
function createCart() {
let items = $state([]);
let total = $derived(
items.reduce((sum, item) => sum + item.price * item.quantity, 0)
);
let itemCount = $derived(
items.reduce((sum, item) => sum + item.quantity, 0)
);
return {
get items() { return items; },
get total() { return total; },
get itemCount() { return itemCount; },
addItem(item: Omit) {
const existing = items.find(i => i.id === item.id);
if (existing) {
existing.quantity++;
} else {
items.push({ ...item, quantity: 1 });
}
},
removeItem(id: number) {
items = items.filter(i => i.id !== id);
},
clear() {
items = [];
}
};
}
export const cart = createCart();
```
```svelte
Items: {cart.itemCount}
Total: ${cart.total.toFixed(2)}
```
### Legacy Svelte Store (Svelte 4 Style)
```typescript
// src/lib/stores/user.ts
import { writable, derived } from 'svelte/store';
interface User {
id: number;
name: string;
email: string;
}
function createUserStore() {
const { subscribe, set, update } = writable(null);
return {
subscribe,
login: (user: User) => set(user),
logout: () => set(null),
updateName: (name: string) => update(u => u ? { ...u, name } : null)
};
}
export const user = createUserStore();
// Derived store
export const isLoggedIn = derived(user, $user => $user !== null);
```
```svelte
{#if $isLoggedIn}
Welcome, {$user?.name}!
{:else}
Please log in
{/if}
```
## Animations and Transitions
### Built-in Transitions
```svelte
{#if visible}
Fades in and out
Slides in and out
Flies in from bottom
{/if}
```
### Custom Transitions
```typescript
// src/lib/transitions.ts
export function blur(node: HTMLElement, { duration = 300 }) {
return {
duration,
css: (t: number) => `
opacity: ${t};
filter: blur(${(1 - t) * 10}px);
`
};
}
```
```svelte
{#if show}
Custom blur transition
{/if}
```
### Animate Directive (FLIP Animations)
```svelte
{#each items as item (item)}
-
{item}
{/each}
```
## Advanced Features
### Actions (Element Behaviors)
```typescript
// src/lib/actions.ts
export function clickOutside(node: HTMLElement, callback: () => void) {
const handleClick = (event: MouseEvent) => {
if (!node.contains(event.target as Node)) {
callback();
}
};
document.addEventListener('click', handleClick, true);
return {
destroy() {
document.removeEventListener('click', handleClick, true);
}
};
}
```
```svelte
{#if showMenu}
{/if}
```
### Slots and Component Composition
```svelte
{#if title}
{title}
{:else}
Default Header
{/if}
Default content
This is the main content
```
### Special Elements
```svelte
Content
console.log('Window resized')}
onkeydown={(e) => console.log(e.key)}
/>
My Page
```
## Migration from React/Vue
### React to Svelte 5
| React | Svelte 5 | Notes |
|-------|----------|-------|
| `useState(0)` | `$state(0)` | Direct state |
| `useMemo(() => x * 2, [x])` | `$derived(x * 2)` | Auto-tracked |
| `useEffect(() => {...}, [x])` | `$effect(() => {...})` | Auto deps |
| `props.name` | `let { name } = $props()` | Destructure |
| `{show && }` | `{#if show}{/if}` | Explicit |
### Vue 3 to Svelte 5
| Vue 3 | Svelte 5 | Notes |
|-------|----------|-------|
| `ref(0)` | `$state(0)` | Direct state |
| `computed(() => x * 2)` | `$derived(x * 2)` | Similar |
| `watch(() => x, ...)` | `$effect(() => {...})` | Auto-tracked |
| `defineProps<{ name: string }>()` | `let { name } = $props()` | Type-safe |
| `v-if="show"` | `{#if show}` | Block syntax |
## Performance Best Practices
1. **Use $derived over $effect** when only computed values are needed
2. **Avoid unnecessary $effect** - only for side effects, not computations
3. **Leverage compiler optimizations** - Svelte does most work at build time
4. **Use keyed each blocks** - `{#each items as item (item.id)}`
5. **Lazy load components** - `const Component = await import('./Heavy.svelte')`
6. **SSR for initial load** - Use SvelteKit's SSR capabilities
7. **Optimize bundles** - Use adapters for deployment targets
## Testing
### Unit Tests with Vitest
```typescript
// Counter.test.ts
import { render, fireEvent } from '@testing-library/svelte';
import { expect, test } from 'vitest';
import Counter from './Counter.svelte';
test('increments counter on click', async () => {
const { getByText } = render(Counter);
const button = getByText('+');
await fireEvent.click(button);
expect(getByText(/Count: 1/)).toBeInTheDocument();
});
```
### E2E with Playwright
```typescript
// tests/login.test.ts
import { expect, test } from '@playwright/test';
test('user can log in', async ({ page }) => {
await page.goto('/login');
await page.fill('input[name="email"]', 'user@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('text=Welcome')).toBeVisible();
});
```
## Deployment
### Adapters
```javascript
// svelte.config.js
import adapter from '@sveltejs/adapter-vercel'; // or adapter-node, adapter-static
export default {
kit: {
adapter: adapter()
}
};
```
**Available Adapters**:
- `adapter-auto`: Auto-detect platform
- `adapter-vercel`: Vercel deployment
- `adapter-node`: Node.js server
- `adapter-static`: Static site generation
- `adapter-cloudflare`: Cloudflare Pages/Workers
- `adapter-netlify`: Netlify deployment
## Resources
- **Svelte Docs**: https://svelte.dev/docs
- **SvelteKit Docs**: https://kit.svelte.dev/docs
- **Svelte 5 Runes**: https://svelte-5-preview.vercel.app/docs/runes
- **Tutorial**: https://learn.svelte.dev
- **REPL**: https://svelte.dev/repl
## Summary
- **Svelte 5** uses Runes API ($state, $derived, $effect) for explicit reactivity
- **Compiler-first** - shifts work to build time for minimal runtime overhead
- **SvelteKit** provides full-stack capabilities with SSR/SSG/SPA modes
- **Write less code** - simpler syntax than React/Vue
- **Exceptional performance** - small bundles, fast runtime
- **Migration-friendly** - Svelte 4 and 5 can coexist
- **Type-safe** - First-class TypeScript support