What Migrating From React to Svelte Taught Us About Reactivity
After years in the React mental model, switching to Svelte's compiler-based approach forced us to rethink how reactivity works from first principles.
We’ve written a lot of React. Hooks, context, Redux, Zustand — we’ve been through the full evolution of state management in the React ecosystem. When we started a new project in Svelte, we expected a learning curve. We didn’t expect it to change how we think about reactivity.
The Virtual DOM Was Never the Point
React’s virtual DOM is an implementation detail that became load-bearing in how people reason about the framework. Reconciliation, memoization, useMemo, useCallback — a significant portion of React expertise is managing the overhead that the virtual DOM creates.
Svelte doesn’t have a virtual DOM. The compiler analyzes your component and generates precise DOM updates. No diffing, no reconciliation, no stale closure bugs from hooks.
The interesting thing: once we stopped thinking about the virtual DOM, component design became simpler. We stopped asking “will this cause an unnecessary re-render?” and started asking “what state does this component actually own?”
Reactivity as a Language Feature
In React, reactivity requires opting in through hooks:
const [count, setCount] = useState(0);
const doubled = useMemo(() => count * 2, [count]);
In Svelte 5, the compiler tracks reactivity through the $state and $derived runes:
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
The difference is more than syntax. With React’s useMemo, you declare the dependencies manually. With $derived, the compiler analyzes the expression and tracks dependencies automatically. Forget a dependency in useMemo? Stale value, subtle bug. Svelte doesn’t have this class of error.
Component Composition
Svelte’s slot system and Svelte 5’s snippets make component composition feel natural. There’s no equivalent of React’s prop drilling ceremony for render props.
<!-- Parent -->
<DataTable data={rows}>
{#snippet cell(row)}
<CustomCell {row} />
{/snippet}
</DataTable>
The snippet is locally scoped and the data flows in a direction that matches how you’d describe the feature in English.
Where React Still Wins
React’s ecosystem is enormous. If you need a specific UI library, data grid, charting component, or animation library, there’s almost certainly a React version that’s mature and well-maintained.
React also has deeper penetration in the enterprise hiring market. A team scaling from 5 to 50 engineers will find React candidates far more easily than Svelte candidates.
And React’s server components, while complex, enable patterns that Svelte’s static compilation doesn’t. For content-heavy sites that need dynamic per-request rendering, Next.js’s server components are genuinely powerful.
The Honest Take
Svelte is a better tool for building applications where you control the whole stack and the team is small. The output is smaller, the mental model is simpler, and the development experience is excellent.
React is the safer choice for large teams, large ecosystems, or organizations where hiring flexibility matters more than technical elegance.
We use both, deliberately, based on the project context.