Under The Hood
frontend svelte Svelte 5 (compiler)

Svelte AST Parser: Reactive Variable Hoisting & JS Lowering

Last updated
Prerequisites:
Svelte component syntax
Understanding of compilers and ASTs
  • svelte
  • compiler
  • ast
  • parser
  • lowering
  • codegen

Read at your depth

The practical view

Svelte compiles your .svelte files into plain JavaScript at build time — there's no runtime framework interpreting your markup. The compiler: (1) parses the template into an AST, (2) analyzes which variables are reactive (read/written in the template), (3) transforms the component into JS that creates DOM nodes and updates them directly. The output includes a create function (initial DOM) and update functions per reactive binding. Svelte 5 also transforms runes ($state, $derived, $effect) into signal calls. You can inspect the output with the Svelte REPL's 'JS output' tab.

The same idea in other frameworks

react equivalent
React uses a runtime (Fiber + reconciler); Svelte compiles away the framework, keeping only signal primitives.

Legacy vs modern

Runtime framework interpretation vs compiled DOM instructions

A runtime approach interprets templates at runtime (Virtual DOM diffing); Svelte compiles the template into direct DOM update code at build time.

before → after
Runtime template interpretation (VDOM)
render(h('div', {}, [text]), container); // ❌ OLD: runtime builds/diffs a virtual tree
Compiled DOM instructions
// compiled output: direct DOM creation + targeted updates
let count = $state(0); // ✅ NEW: compiled to signal(0)

Interview gotchas

Context

This tests the compiler's dependency analysis — interviewers want to know how reactivity is determined at compile time and how the runes change simplified that determination.

The mechanical answer

In Svelte 4, reactivity was inferred: the compiler analyzed which top-level variables were referenced in the template and assigned anywhere in the script (assignment = potential invalidation). This inference was heuristic — it could miss indirect mutations (array.push without reassignment needed explicit reassignment) and required the compiler to build an invalidation graph per component. In Svelte 5 with runes, reactivity is explicit: you annotate state with $state, derivations with $derived, and effects with $effect. The compiler no longer guesses; it transforms the annotated declarations into signals and tracks reads/writes through the signal runtime. This makes the analysis deterministic and removes the Svelte 4 edge cases (mutating objects without reassignment, $: ordering).

Trap

The naive answer is 'Svelte makes all variables reactive'. Only state explicitly marked (or inferred by the old heuristics) is reactive; plain let in runes mode is NOT reactive unless wrapped in $state. Another trap: assuming the compiler tracks deep mutations automatically — in Svelte 5, mutating a $state object's property is tracked because the runtime uses signals/proxies, but in Svelte 4 you needed reassignment. Candidates who can compare the inference vs explicit-annotation models show real compiler understanding.

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

Third-party licenses Press ⌘ K to search.