The migration command is a patch generator.
SvelteKit 3 is now stable. The release post points existing projects to npx sv migrate sveltekit-3 --tasks all --confirm. The command migrates what it can and generates a TODO list for work it cannot finish automatically.[1]
That contract is better than pretending a codemod can understand every application. It gives automation the mechanical edits and leaves ambiguous work visible. Keep the generated TODO list in the review packet. Do not treat an empty terminal exit as proof that the application survived.
A codemod can move syntax. It cannot certify the behavior that syntax used to produce.
Raise the floor before changing the room.
The migration guide recommends moving to the latest SvelteKit 2 release first so targeted deprecation warnings can expose old usage before the major upgrade. SvelteKit 3 also raises minimum versions for Node, TypeScript, Svelte, and Vite. The documented floors are Node 22.17, TypeScript 6, Svelte 5.57.1, and Vite 8.0.12.[2]
Record those versions in the baseline commit. Run the current build and tests before the migration. If the baseline is already red, the new patch cannot tell you which failure belongs to the upgrade.
Configuration and imports move through real boundaries.
SvelteKit configuration now belongs in the sveltekit Vite plugin instead of svelte.config.js. The $lib alias becomes the standard #lib subpath import. Environment variables and service worker imports also change. Error handling now routes more errors through handleError.[1][2]
These are not one kind of change. Configuration affects builds and adapters. Import changes affect resolution. Environment changes affect public and private data. Service workers affect offline and update behavior. Error changes affect logging and user-visible failure paths. Review and replay each boundary separately.
Use task selection to make smaller patches.
The CLI supports task-based migrations. It can limit files with --files, select work with --tasks, choose a package manager with --install, or skip installation with --no-install. The default Git check can be bypassed with --no-git-check.[3]
Keep the Git check unless an isolated throwaway worktree provides the same protection. On a large application, run bounded task groups and review each patch before starting the next. Smaller patches preserve the reason for each change and make rollback cheaper.
Remote functions are not part of the stable promise yet.
The stable release says remote functions still depend on Async Svelte and an experimental flag. Do not bundle their adoption into a routine SvelteKit 3 migration. Upgrade the framework first. Evaluate the experimental feature as a separate change with its own rollback and evidence.[1]