The Compiler Model
React ships a JavaScript runtime to every user’s browser — roughly 45 kB gzip for React + ReactDOM. That runtime maintains a virtual DOM tree, diffs it on every state change, and patches the real DOM. Svelte takes a fundamentally different approach: it is a compiler. Your .svelte files are transformed into plain, framework-free JavaScript at build time. By the time your code reaches the browser there is no Svelte runtime to speak of — just the direct DOM instructions the compiler emitted.
How the mental models differ
Section titled “How the mental models differ”// React: ships a runtime// 1. render() builds a virtual DOM tree// 2. diffing algorithm compares old vs new vDOM// 3. React patches only the changed real DOM nodes//// Every user downloads React + ReactDOM (~45 kB gzip)// before your app code even runs.
function Counter() { const [count, setCount] = React.useState(0); // On every click React re-runs this function, // builds a new vDOM, diffs, then patches. return <button onClick={() => setCount(c => c + 1)}>{count}</button>;}// Svelte: compiles at build time// Your .svelte file → plain JS at npm run build//// The compiler sees: let count = $state(0)// and emits something like:// element.textContent = count (direct DOM update)//// No runtime framework is shipped to the browser.
<script> let count = $state(0);</script>
<!-- The compiler turns this into a targeted DOM update --><button onclick={() => count++}>{count}</button>The key insight: React’s mental model is render → diff → patch happening at runtime in the browser. Svelte’s mental model is compile → direct DOM update — the “diffing” is done statically by the compiler before your code ever ships.
Try it: a compiled counter
Section titled “Try it: a compiled counter”The component below demonstrates the compiler model in practice. Notice that there is no useState, no setter function, and no reconciler. The compiler analyses which DOM nodes depend on count and emits targeted updates — only those nodes change when you click a button.