Migrating a Vue codebase to Svelte, one route at a time
Moving a production platform from Vue to Svelte without a feature freeze or a long-lived branch, and what the framework switch actually costs a team.
The proposal that gets rejected, correctly, is the one that opens with "we stop shipping features for a quarter." No business takes that trade. So the migration had to be a sequence of changes that each ship on their own.
Route-level boundaries
The unit of migration is the route, not the component. A route already has a clean contract with the rest of the app: a URL, some query params, and whatever lives in the shared store. Components do not, which is why going component by component turns into an interop problem.
Each migrated route deploys on its own. If one regresses, the rollback is that route.
Keeping the design system in one place
The component library is the hard dependency. Two implementations means two sources of truth for every button state, and they will drift. I pushed the design decisions down into tokens that neither framework owns.
/* Tokens are framework-agnostic, so both implementations
render the same button without sharing code. */
:root {
--control-height: 2.25rem;
--control-radius: 0.5rem;
--control-padding-inline: 0.875rem;
--control-bg: var(--primary);
--control-fg: var(--primary-foreground);
}With tokens in place, the Vue button and the Svelte button are thin wrappers over the same values. A visual change is a token change, reviewed once.
What transfers and what does not
- Reactivity intuition transfers almost completely. Runes and the Composition API are the same mental model with different syntax.
- Store patterns transfer partially. Anything built around Vue plugin injection needs rethinking rather than porting.
- Build tooling transfers cleanly, since both sit on Vite.
- Team habits transfer slowest, and they set the actual timeline.
Where it stands
Several routes are live in Svelte, the token layer is shared by both frameworks, and the team ships at the same cadence as before. There was no freeze and no long-lived branch, and there will not be a launch day.