Skip to main content
Effects are functions that run when state updates, and can be used for things like calling third-party libraries, drawing on <canvas> elements, or making network requests. They only run in the browser, not during server-side rendering.

Signature

fn
() => void | (() => void)
The effect function to run. Can optionally return a teardown function.
When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside untrack), and re-runs the function when that state later changes.
Generally speaking, you should not update state inside effects, as it will make code more convoluted and will often lead to never-ending update cycles.

Understanding lifecycle

Your effects run after the component has been mounted to the DOM, and in a microtask after state changes. Re-runs are batched (i.e. changing color and size in the same moment won’t cause two separate runs), and happen after any DOM updates have been applied. You can use $effect anywhere, not just at the top level of a component, as long as it is called while a parent effect is running.
Svelte uses effects internally to represent logic and expressions in your template — this is how <h1>hello {name}!</h1> updates when name changes.

Teardown functions

An effect can return a teardown function which will run immediately before the effect re-runs:
Teardown functions also run when the effect is destroyed, which happens when its parent is destroyed (for example, a component is unmounted) or the parent effect re-runs.

Understanding dependencies

$effect automatically picks up any reactive values ($state, $derived, $props) that are synchronously read inside its function body (including indirectly, via function calls) and registers them as dependencies. When those dependencies change, the $effect schedules a re-run.
If $state and $derived are used directly inside the $effect (for example, during creation of a reactive class), those values will not be treated as dependencies.
Values that are read asynchronously — after an await or inside a setTimeout, for example — will not be tracked:
An effect only reruns when the object it reads changes, not when a property inside it changes:

$effect.pre

In rare cases, you may need to run code before the DOM updates. For this we can use the $effect.pre rune:
Apart from the timing, $effect.pre works exactly like $effect.

$effect.tracking

The $effect.tracking rune is an advanced feature that tells you whether or not the code is running inside a tracking context, such as an effect or inside your template:
It is used to implement abstractions like createSubscriber, which will create listeners to update reactive values but only if those values are being tracked.

$effect.pending

When using await in components, the $effect.pending() rune tells you how many promises are pending in the current boundary, not including child boundaries:

$effect.root

The $effect.root rune is an advanced feature that creates a non-tracked scope that doesn’t auto-cleanup. This is useful for nested effects that you want to manually control:

When not to use $effect

In general, $effect is best considered something of an escape hatch — useful for things like analytics and direct DOM manipulation — rather than a tool you should use frequently. In particular, avoid using it to synchronise state.
For things that are more complicated than a simple expression like count * 2, you can also use $derived.by.