--- title: Best practices skill: true name: svelte-core-bestpractices description: Svelte best practices for writing, editing, or reviewing Svelte/SvelteKit components and modules. Use when touching Svelte reactivity, props, events, snippets, each blocks, styling, context, actions/attachments, stores, or Svelte 5 runes. --- ## Process 1. Identify the Svelte mode before changing code. - Check `package.json` and existing components. - If the project already uses Svelte 5 runes, write new code in runes mode. - If the touched area is legacy Svelte and a runes migration is not requested, keep the local style consistent. - Done when the edit has one clear syntax mode for the touched files. 2. Put reactivity in the narrowest primitive that fits. - Local reactive state: `$state`. - Computed value: `$derived` or `$derived.by`. - Side effect or external subscription: `$effect`, `{@attach ...}`, `createSubscriber`, or an event handler, depending on the trigger. - Done when no `$effect` is being used just to compute state. 3. Keep state scoped. - Component-only values stay local. - Shared state that must be scoped to a subtree uses context. - Shared module state is acceptable only when cross-user leakage is impossible or irrelevant. - Done when SSR state cannot leak between users. 4. Review DOM boundaries. - Lists use keyed each blocks with stable object identity. - Global listeners use `` or `` when possible. - Parent-to-child styling uses CSS custom properties before `:global`. - Done when the DOM update and cleanup paths are explicit. ## `$state` Use `$state` only for values that should update a template expression, `$derived`, or `$effect`. Normal variables are fine for everything else. Objects and arrays created with `$state({ ... })` or `$state([ ... ])` are deeply reactive. Mutation triggers updates, but proxying has overhead. For large values that are only reassigned, such as API responses, use `$state.raw`. Use `$state.snapshot` before passing proxy state to an external API or storing a moment-in-time copy. Rune-enabled `.svelte.js`/`.svelte.ts` modules should export factories or objects with getters and named mutation methods. Do not export a rune variable that is reassigned internally, and avoid module-global mutable state when instances or SSR requests need isolation. ## `$derived` Use `$derived` for computed values. ```js let square = $derived(num * num); ``` Use `$derived.by` when the computation needs a function body. ```js let total = $derived.by(() => { return items.reduce((sum, item) => sum + item.price, 0); }); ``` Do not use `$effect` to assign ordinary computed state. ```js // avoid let square; $effect(() => { square = num * num; }); ``` Derived values are writable, but they re-evaluate when their dependencies change. If a derived expression returns an object or array, Svelte returns it as-is; it is not made deeply reactive. ## `$effect` Use `$effect` as an escape hatch for real side effects. Avoid writing Svelte state inside effects. Choose the tighter tool when one exists: - External library sync, such as D3: `{@attach ...}`. - User-triggered work: the event handler or a function binding. - Debug logging: `$inspect`. - External reactive source: `createSubscriber` from `svelte/reactivity`. Effects do not run on the server, so `if (browser) { ... }` inside an effect is unnecessary. ## `$props` Treat props as changing values. Values that depend on props should usually be derived. ```js let { type } = $props(); let color = $derived(type === 'danger' ? 'red' : 'green'); ``` This stale version should be avoided: ```js let { type } = $props(); let color = type === 'danger' ? 'red' : 'green'; ``` ## `$bindable` Use `$bindable` only when a child is intentionally an input-like controller for a parent-owned value. Keep domain operations such as add, save, or delete as callback props so mutation ownership stays visible. ## `$inspect.trace` Use `$inspect.trace(label)` to debug reactivity. Put it as the first line of an `$effect`, `$derived.by`, or a function called by them. It shows which dependency triggered the update. ## Events In modern Svelte, event listeners are element attributes that start with `on`. ```svelte ``` For global targets, prefer Svelte elements over manual lifecycle wiring. ```svelte ``` ## Snippets Use snippets for reusable markup that can be rendered with `{@render ...}` or passed as props. ```svelte {#snippet greeting(name)}

hello {name}!

{/snippet} {@render greeting('world')} ``` Declare snippets in the template. Top-level snippets can be referenced from `