Compiler vs Runtime
This is the biggest architectural difference between React and Svelte, and it shapes everything else. React is a runtime library — it ships to the browser and reconciles a virtual DOM on every state change. Svelte is a compiler — it analyses your components at build time and outputs plain JavaScript that updates the DOM directly. By the time your code reaches the browser, Svelte itself is largely gone.
What React ships to the browser
Section titled “What React ships to the browser”React bundles a reconciler, a fiber scheduler, synthetic event system, and hooks runtime — all of this runs on every user’s device, on every page load. When state changes, React builds a new virtual DOM tree, diffs it against the previous tree, and then flushes the minimal set of real DOM changes. That diff step happens at runtime, in the browser.
What Svelte ships to the browser
Section titled “What Svelte ships to the browser”Svelte analyses your component’s template and state at build time and generates targeted imperative DOM update code. When count changes, the compiled output calls textContent = count — one direct DOM write, no diffing, no reconciler involved. The Svelte “runtime” that ships is tiny (a handful of utility functions for things like {#each} keyed lists and transitions).
Side-by-side mental model
Section titled “Side-by-side mental model”// React — ships reconciler + fiber + hooks runtime// On every setState:// 1. Re-run the function component// 2. Build a new virtual DOM tree// 3. Diff against the previous tree// 4. Flush real DOM changes
function Counter() { const [count, setCount] = React.useState(0); return ( <button onClick={() => setCount(c => c + 1)}> Count: {count} </button> );}<!-- Svelte — compiles to direct DOM code --><!-- On count change, compiler emits roughly: buttonText.data = "Count: " + count; No diffing. No reconciler. -->
<script> let count = $state(0);</script>
<button onclick={() => count++}> Count: {count}</button>What this means for you as a developer
Section titled “What this means for you as a developer”Bundle size: A React + ReactDOM bundle is ~42 kB gzipped minimum, before your app. Svelte adds almost nothing — the output is your app code plus a tiny shared runtime.
Performance: No virtual DOM diffing means less work per state change. For most UIs this difference is imperceptible, but it becomes meaningful for large lists, animations, or low-end devices.
Mental model: You write declarative components exactly as you do in React. The compiler handles the imperative DOM work for you. You do not have to think about how it works — just know that count++ updates every place count appears in the template, automatically.
No stale closures from diffing: Because Svelte does not re-run your entire component function on each update (the way React re-renders a function component), the class of bugs around stale closures in React hooks does not exist in the same form in Svelte.
Try it: see reactivity in action
Section titled “Try it: see reactivity in action”$derived is the Svelte equivalent of useMemo — it recomputes automatically when its dependencies change. No dependency array required; Svelte’s compiler tracks dependencies for you.