The $effect Rune
Effects synchronize with the outside world
Section titled “Effects synchronize with the outside world”$effect runs a function after the DOM has updated, and re-runs it whenever the reactive values it reads change. It is for side effects — synchronizing Svelte state with things outside Svelte: the DOM directly, a third-party library, a subscription, a timer, logging, localStorage.
<script> let count = $state(0);
$effect(() => { // Runs after render, and again whenever count changes. document.title = `Count: ${count}`; });</script>Dependencies are tracked automatically, exactly like $derived — the effect reads count, so it re-runs when count changes. No dependency array.
Cleanup
Section titled “Cleanup”If an effect sets something up that must be torn down — an interval, an event listener, a subscription — return a cleanup function. Svelte runs it before the effect re-runs and when the component is destroyed.
<script> let seconds = $state(0);
$effect(() => { const id = setInterval(() => seconds++, 1000); return () => clearInterval(id); // cleanup: runs before re-run and on destroy });</script>$effect.pre
Section titled “$effect.pre”$effect runs after the DOM updates. Occasionally you need to read the DOM before it updates — for example, to capture scroll position before new content pushes it. $effect.pre runs before the DOM update instead, with the same tracking and cleanup rules.
<script> let messages = $state([]);
$effect.pre(() => { messages.length; // track the dependency // read scroll position BEFORE the DOM updates with new messages });</script>You probably do not need an effect
Section titled “You probably do not need an effect”This is the most important guidance in the module. Effects are an escape hatch, and reaching for them to manage internal state is the most common Svelte 5 mistake. Before writing an effect, ask:
- Computing a value from state? Use
$derived, not an effect that assigns state. - Responding to a user action? Do the work in the event handler (
onclick), not in an effect watching a variable. - Mirroring a prop into state? Usually a design smell — derive from the prop instead.
flowchart TB q["Need to react to state?"] --> derive["Computing a value? → $derived"] q --> handler["From a user action? → event handler"] q --> effect["Syncing with something OUTSIDE Svelte? → $effect"]
An effect is the right tool only when you are bridging to something Svelte doesn’t control — the document title, a canvas, a websocket, localStorage, an analytics call. If the work stays inside Svelte’s reactive world, a rune like $derived almost always fits better.