From 6e9b2a6fd85e01a12aaca4b883eea4d15ae14d36 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 27 Feb 2026 15:35:19 -0500 Subject: [PATCH] docs: best practices (#17804) Based on #17727 but with a few changes: - smaller (fewer tokens) - removed some bits that are really just summarising existing docs - added an explicit 'don't use these legacy features' section - shuffled some things around a bit --------- Co-authored-by: paoloricciuti Co-authored-by: Federico Varano <50919335+fvarano@users.noreply.github.com> Co-authored-by: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> --- .../docs/07-misc/01-best-practices.md | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 documentation/docs/07-misc/01-best-practices.md diff --git a/documentation/docs/07-misc/01-best-practices.md b/documentation/docs/07-misc/01-best-practices.md new file mode 100644 index 0000000000..ac275e4d9a --- /dev/null +++ b/documentation/docs/07-misc/01-best-practices.md @@ -0,0 +1,184 @@ +--- +title: Best practices +name: svelte-core-bestpractices +description: Guidance on writing fast, robust, modern Svelte code. Load this skill whenever in a Svelte project and asked to write/edit or analyze a Svelte component or module. Covers reactivity, event handling, styling, integration with libraries and more. +--- + + +This document outlines some best practices that will help you write fast, robust Svelte apps. It is also available as a `svelte-core-bestpractices` skill for your agents. + + +## `$state` + +Only use the `$state` rune for variables that should be _reactive_ — in other words, variables that cause an `$effect`, `$derived` or template expression to update. Everything else can be a normal variable. + +Objects and arrays (`$state({...})` or `$state([...])`) are made deeply reactive, meaning mutation will trigger updates. This has a trade-off: in exchange for fine-grained reactivity, the objects must be proxied, which has performance overhead. In cases where you're dealing with large objects that are only ever reassigned (rather than mutated), use `$state.raw` instead. This is often the case with API responses, for example. + +## `$derived` + +To compute something from state, use `$derived` rather than `$effect`: + +```js +// @errors: 2451 +let num = 0; +// ---cut--- +// do this +let square = $derived(num * num); + +// don't do this +let square; + +$effect(() => { + square = num * num; +}); +``` + +> [!NOTE] `$derived` is given an expression, _not_ a function. If you need to use a function (because the expression is complex, for example) use `$derived.by`. + +Deriveds are writable — you can assign to them, just like `$state`, except that they will re-evaluate when their expression changes. + +If the derived expression is an object or array, it will be returned as-is — it is _not_ made deeply reactive. You can, however, use `$state` inside `$derived.by` in the rare cases that you need this. + +## `$effect` + +Effects are an escape hatch and should mostly be avoided. In particular, avoid updating state inside effects. + +- If you need to sync state to an external library such as D3, it is often neater to use [`{@attach ...}`](@attach) +- If you need to run some code in response to user interaction, put the code directly in an event handler or use a [function binding](bind#Function-bindings) as appropriate +- If you need to log values for debugging purposes, use [`$inspect`]($inspect) +- If you need to observe something external to Svelte, use [`createSubscriber`](svelte-reactivity#createSubscriber) + +Never wrap the contents of an effect in `if (browser) {...}` or similar — effects do not run on the server. + +## `$props` + +Treat props as though they will change. For example, values that depend on props should usually use `$derived`: + +```js +// @errors: 2451 +let { type } = $props(); + +// do this +let color = $derived(type === 'danger' ? 'red' : 'green'); + +// don't do this — `color` will not update if `type` changes +let color = type === 'danger' ? 'red' : 'green'; +``` + +## `$inspect.trace` + +`$inspect.trace` is a debugging tool for reactivity. If something is not updating properly or running more than it should you can add `$inspect.trace(label)` as the first line of an `$effect` or `$derived.by` (or any function they call) to trace their dependencies and discover which one triggered an update. + +## Events + +Any element attribute starting with `on` is treated as an event listener: + +```svelte + + + + + + + +``` + +If you need to attach listeners to `window` or `document` you can use `` and ``: + +```svelte + + +``` + +Avoid using `onMount` or `$effect` for this. + +## Snippets + +[Snippets](snippet) are a way to define reusable chunks of markup that can be instantiated with the [`{@render ...}`](@render) tag, or passed to components as props. They must be declared within the template. + +```svelte +{#snippet greeting(name)} +

hello {name}!

+{/snippet} + +{@render greeting('world')} +``` + +> [!NOTE] Snippets declared at the top level of a component (i.e. not inside elements or blocks) can be referenced inside `