Svelte 5 Best Practices
Quick Reference
Topic When to Use Reference
Runes $state, $derived, $effect, $props, $bindable, $inspect runes.md
Snippets Replacing slots, {#snippet}, {@render} snippets.md
Events onclick handlers, callback props, context API events.md
TypeScript Props typing, generic components typescript.md
Migration Svelte 4 to 5, stores to runes migration.md
SvelteKit Load functions, form actions, SSR, page typing sveltekit.md
Performance Universal reactivity, avoiding over-reactivity, streaming performance.md
Essential Patterns
Reactive State
<script> let count = $state(0); // Reactive state let doubled = $derived(count * 2); // Computed value </script>
Component Props
<script> let { name, count = 0 } = $props(); let { value = $bindable() } = $props(); // Two-way binding </script>
Snippets (replacing slots)
<script> let { children, header } = $props(); </script>
{@render header?.()} {@render children()}
Event Handlers
<!-- Svelte 5: use onclick, not on:click --> <button onclick={() => count++}>Click</button>
Callback Props (replacing createEventDispatcher)
<script> let { onclick } = $props(); </script>
<button onclick={() => onclick?.({ data })}>Click</button>
Common Mistakes
-
Using let without $state
-
Variables are not reactive without $state()
-
Using $effect for derived values - Use $derived instead
-
Using on:click syntax - Use onclick in Svelte 5
-
Using createEventDispatcher
-
Use callback props instead
-
Using <slot>
-
Use snippets with {@render}
-
Forgetting $bindable()
-
Required for bind: to work
-
Setting module-level state in SSR - Causes cross-request leaks
-
Sequential awaits in load functions - Use Promise.all for parallel requests