Why Svelte, the Compiler
Runtime frameworks vs a compiler
Section titled “Runtime frameworks vs a compiler”Most UI frameworks are runtime libraries. You ship the framework to the browser, and at runtime it maintains a virtual DOM, re-runs your components when state changes, diffs the new virtual tree against the old one, and applies the differences. That machinery — the reconciler, the scheduler — is code the user downloads and the CPU runs on every update.
Svelte takes the work out of the browser and into the build step. The Svelte compiler reads your components ahead of time, figures out precisely which DOM nodes depend on which state, and emits plain JavaScript that updates exactly those nodes. There is no virtual DOM to ship, no diffing at runtime.
flowchart TB
subgraph runtime["Runtime framework"]
ship["ship framework + components"] --> vdom["runtime keeps a virtual DOM"]
vdom --> diff["diff on every state change"]
end
subgraph svelte["Svelte (compiler)"]
build["compile components at build time"] --> emit["emit precise update code"]
emit --> tiny["ship tiny JS, no diffing"]
end What “no virtual DOM” buys you
Section titled “What “no virtual DOM” buys you”- Smaller bundles. You don’t ship a reconciler. A Svelte component compiles to roughly the imperative code you’d hand-write to update those exact nodes, so there’s little framework overhead riding along.
- Less runtime work. When
countchanges, there’s no tree to re-create and diff — the generated code updates the one text node that showscount. Updates are surgical by construction. - Less indirection. The gap between “what I wrote” and “what runs” is small: the compiler’s output is close to what you’d write by hand.
This is why Svelte is sometimes called “the disappearing framework” — much of it compiles away, leaving mostly your logic plus a thin helper layer.
What the compiler actually produces
Section titled “What the compiler actually produces”Given a component with let count = $state(0) and <p>{count}</p>, the compiler statically sees that the text node depends on count. It generates code that (1) creates the <p> once, and (2) registers that when count changes, this specific text node’s content is updated — nothing else. Multiply that across a whole app and you get updates that touch only what changed, without any runtime bookkeeping to figure out what changed.
<script> let count = $state(0);</script>
<!-- The compiler knows this text node — and only this one — depends on count. --><button onclick={() => count++}>clicked {count} times</button>You write declarative components; the compiler writes the imperative DOM code. That division of labor is the entire value proposition.