Svelte 13: $effect — Side Effects
easy⏱ 5 mincoursesvelte
$effect re-runs on every dependency change
Read any $state or $derived value inside $effect's callback, and Svelte subscribes to it automatically — no dependency array to maintain by hand. Write to a $state value from INSIDE an $effect and you can trigger another effect run, so effects are best used for synchronizing with the outside world, not for deriving one piece of state from another (that's what $derived is for).
<script>
let query = $state('');
$effect(() => {
console.log('Searching for:', query);
});
</script>
Cleanup runs before the next run, and on destroy
The debounced auto-save below starts a setTimeout every time note changes. Without cleanup, typing quickly would stack up dozens of pending timeouts, all eventually firing. Returning () => clearTimeout(id) tells Svelte 'cancel the PREVIOUS pending save before scheduling a new one' — so only the latest keystroke's timeout ever survives to fire.
<script>
let note = $state('');
let savedAt = $state(null);
$effect(() => {
const id = setTimeout(() => {
localStorage.setItem('note', note);
savedAt = new Date().toLocaleTimeString();
}, 600);
return () => clearTimeout(id); // cancels the stale save
});
</script>
Other classic $effect uses: document.title, subscriptions
Syncing document.title to reflect app state, opening/closing a WebSocket connection, attaching a global resize listener, driving a <canvas> animation loop — these are all textbook $effect use cases because they all reach OUTSIDE the reactive graph into the DOM, the network, or browser APIs.