Under The Hood
frontend svelte Svelte 5 (runes)

$derived() Memoization vs $effect() Microtask Scheduling

Last updated
Prerequisites:
Svelte 5 runes basics ($state)
Understanding of reactive values vs side effects
  • svelte
  • runes
  • derived
  • effect
  • microtask
  • reactivity

Read at your depth

The practical view

$derived computes a value from reactive state: let double = $derived(count * 2);. It recomputes lazily when count changes and is read. $effect runs code after state changes: $effect(() => { console.log(count); });. It runs once initially, then re-runs whenever its read state changes. Use $derived for derived values (it's cached), $effect for side effects (DOM, subscriptions, logging). In Svelte 5 runes you replace Svelte 4's reactive statements ($: double = count * 2) with $derived, and auto-subscriptions with explicit $effect.

The same idea in other frameworks

react equivalent
useMemo ≈ $derived (cached); useEffect ≈ $effect, though React effects run after commit per render.

Legacy vs modern

Svelte 4 $: reactive statement vs Svelte 5 $derived/$effect

The old $: syntax mixed derived values and side effects ambiguously; runes split them into explicit, memoized $derived and effectful $effect.

before → after
Svelte 4 $: statements
$: double = count * 2; // ❌ OLD: reactive statement for a derived value
$: console.log('count', count); // ❌ OLD: side effect mixed into the same syntax
Svelte 5 runes
let double = $derived(count * 2); // ✅ NEW: memoized derived value
$effect(() => console.log('count', count)); // ✅ NEW: explicit side effect

Interview gotchas

Context

This tests whether you understand the caching semantics of derived state — interviewers want to know why derived values don't recompute on every render, unlike plain template expressions.

The mechanical answer

$derived creates a computation node that caches its result. It recomputes only when (a) at least one of the signals it read during its last evaluation changed, and (b) something actually reads the derived value. This is lazy memoization with invalidation. A plain expression in the template (e.g. {count * 2}) is re-evaluated when its surrounding template binding re-runs, which may be more often and without caching. The memoization matters when the derived computation is expensive (filtering a large array, formatting): multiple reads of the same $derived in one update cycle share one cached result, whereas repeating the expression recomputes each time. The equality check (===) also suppresses downstream updates when the derived value didn't actually change.

Trap

The naive answer is '$derived recomputes whenever state changes'. It recomputes lazily on read, and only if a dependency changed. Another trap: assuming a $derived with no readers ever runs — it doesn't (lazy), so side effects placed inside a $derived body may never fire. Candidates who explain the lazy read-triggered recomputation and equality suppression show real understanding.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.