Skip to content

Lifecycle

In Svelte 4, you reached for lifecycle hooks (onMount, beforeUpdate, afterUpdate) for anything involving the DOM or timing. In Svelte 5, $effect covers most of that: it runs after the DOM updates, re-runs when its dependencies change, and its returned cleanup function handles teardown.

<script>
let count = $state(0);
$effect(() => {
document.title = `Count: ${count}`; // runs after mount and on every change
return () => { document.title = 'App'; }; // cleanup on destroy / before re-run
});
</script>

So before reaching for a lifecycle function, ask whether an effect fits. Often it does.

Two lifecycle functions remain genuinely useful:

  • onMount(fn) runs once after the component is first rendered to the DOM, only in the browser (never during SSR). It’s the right place for browser-only setup: measuring the DOM, initializing a canvas or map library, starting an interval. If fn returns a function, it’s called on destroy.
  • onDestroy(fn) runs when the component is removed — for cleanup that isn’t tied to a specific effect (unsubscribing, clearing timers).
<script>
import { onMount, onDestroy } from 'svelte';
onMount(() => {
const chart = new Chart(canvasEl); // browser-only library
return () => chart.destroy(); // cleanup on unmount
});
onDestroy(() => console.log('gone'));
</script>

The key distinction from $effect: onMount runs exactly once and only in the browser, which is precisely what you want for one-time, browser-only initialization. An effect that reads no reactive state also runs once, but onMount states that intent clearly and guarantees browser-only execution.

flowchart LR
  create["component created"] --> mount["onMount (browser, once)"]
  mount --> effects["$effect runs after DOM updates"]
  effects --> effects
  effects --> destroy["onDestroy + effect cleanups"]
Component lifecycle moments

Svelte batches DOM updates. When you change state and need the DOM to reflect it before your next line runs (to measure an element, or focus a freshly-shown input), await tick() resolves once pending changes are applied.

<script>
import { tick } from 'svelte';
async function addAndScroll() {
items.push(newItem);
await tick(); // wait for the new row to be in the DOM
list.scrollTop = list.scrollHeight;
}
</script>
In Svelte 5, what covers most former lifecycle-hook use cases?
What is distinctive about `onMount`?
What does `await tick()` do?
Where should you initialize a browser-only charting library?