Svelte 5 Overview
Svelte 5 is a major release representing a fundamental evolution of the framework. The new reactivity system called “Runes” enables more explicit and predictable code.
flowchart TB
subgraph Svelte5["Svelte 5 Major Changes"]
subgraph Runes["Runes (New Reactivity)"]
R1["$state() - Reactive state declaration"]
R2["$derived() - Computed values"]
R3["$effect() - Side effects"]
R4["$props() - Component properties"]
R5["$bindable() - Two-way bindable props"]
end
subgraph Perf["Performance Improvements"]
P1["Up to 2x faster"]
P2["Reduced bundle size"]
P3["Improved memory usage"]
P4["More efficient diffing"]
end
subgraph DX["Developer Experience"]
D1["Enhanced TypeScript support"]
D2["More explicit reactivity"]
D3["Easier debugging"]
D4["Gradual migration path"]
end
end
Runes Basics
$state - Reactive State
Name: {user.name}
{#each items as item}
- {item}
{/each}
$derived - Derived State
Count: {count}
Doubled: {doubled}
Stats: Sum={stats.sum}, Avg={stats.avg}
$effect - Side Effects
Component Properties
$props
$bindable - Two-Way Binding
value = e.currentTarget.value}
/>
Hello, {name}!
Snippets
{#snippet row(item)}
{item.name}
${item.price}
{/snippet}
{#snippet header()}
Name
Price
{/snippet}
{@render header()}
{#each items as item (item.id)}
{@render row(item)}
{/each}
Svelte 4 vs Svelte 5 Comparison:
| Feature | Svelte 4 | Svelte 5 |
|---|---|---|
| Reactive Variables | let count = 0; | let count = $state(0); |
| Derived Values | $: doubled = c * 2; | let doubled = $derived(c*2); |
| Side Effects | $: console.log(c); | $effect(() => log(count)); |
| Properties | export let name; | let { name } = $props(); |
Event Handling
console.log(e.detail)} />
Class Components
Migration
Automatic Migration
# Use svelte-migrate
npx sv migrate svelte-5
# Or specific file
npx sv migrate svelte-5 src/components/Button.svelte
Gradual Migration
// svelte.config.js
export default {
compilerOptions: {
// Disable Runes for legacy mode
runes: false
}
};
SvelteKit Integration
// +page.svelte
<script>
let { data } = $props();
let posts = $state(data.posts);
let search = $state('');
let filtered = $derived(
posts.filter(p => p.title.toLowerCase().includes(search.toLowerCase()))
);
</script>
<input bind:value={search} placeholder="Search..." />
{#each filtered as post (post.id)}
<article>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
{/each}
Performance Improvements
Svelte 5 Performance Comparison (js-framework-benchmark):
| Metric | Svelte 4 | Svelte 5 | Improvement |
|---|---|---|---|
| DOM Operation Speed | 1.0x | 0.5x | 2x faster |
| Bundle Size (Hello World) | 3.2KB | 2.8KB | -12.5% |
| Memory Usage | 100% | 70% | -30% |
Summary
| Feature | Svelte 4 | Svelte 5 |
|---|---|---|
| Reactive variable | let x = 0 | let x = $state(0) |
| Derived value | $: y = x * 2 | let y = $derived(x * 2) |
| Side effect | $: { ... } | $effect(() => { ... }) |
| Properties | export let prop | let { prop } = $props() |
| Slots | <slot /> | {@render children()} |
| Events | on:click | onclick |