Build1 publisher3 min readPublished
SvelteKit 3.0 puts a Node, TypeScript and Vite upgrade ahead of the framework migration
SvelteKit 3.0 requires Node 22.17, TypeScript 6 and Svelte 5.56.4 or newer before any app code changes. Teams have a toolchain project to schedule and ship before they reach the config move and the rewrite of every $lib import.
The Engineer · Build desk

What happened
- The migration guide recommends moving to the latest 2.x release first, since its deprecation warnings map one to one onto the 3.0 breaking changes.
- svelte.config.js is no longer supported, and the old config.kit options become top-level options on the sveltekit() plugin call in vite.config.ts.
- SvelteKit no longer generates the $lib alias, so projects declare a #lib entry under the imports field of package.json and rename imports across the codebase.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint A team that held TypeScript at 5 for one plugin cannot start the upgrade until that plugin works on TypeScript 6.
- cost Projects that import from src/lib without file extensions face an edit across the whole tree before their #lib imports resolve.
- decision Teams have to choose whether the toolchain bump ships on 2.x as its own deploy or rides in the same branch as SvelteKit 3.0.
The checklist behind this account was written by a dev.to author who read the release announcement, the release-candidate post and the full migration guide end to end [14]. "I have not yet run this migration on a production app, so this is not a war story," the author wrote [13].
The guide sets five version floors [2][1]. The TypeScript floor is the one most likely to wait on someone else. The author expects it to catch teams that pinned TypeScript 5 for plugin compatibility [4]. The Vite step is the one I would ship by itself, because 8.0.12 is the release that bundles stable Rolldown v1 [3]. A build that breaks after Vite and SvelteKit move in the same branch has two suspects.
The guide wants teams on the most recent 2.x release before the jump, for its deprecation warnings [5]. The post does not say whether that release runs on Vite 8 and vite-plugin-svelte 7. If it does, the work splits into three deploys:
1. Move to the latest 2.x and clear every deprecation warning it prints [5]. 2. Raise Node, TypeScript, Svelte, Vite and the Svelte Vite plugin to the 3.0 floors while still on 2.x [2]. 3. Upgrade to SvelteKit 3.0 and work through the breaking changes [1].
If it does not, steps 2 and 3 become one branch, and the two suspects come back.
The release-candidate post gives a sound reason for the config move. The Vite plugin used to resolve the SvelteKit config through an async process that could not start until the entire Vite config was resolved, because tools like Vitest can run from a working directory that is not the project root [7]. Options passed straight to the sveltekit() call are available to the plugin at once [7]. The author put it more briefly: "why were we maintaining two config files for one project?" [15]. Three options go in the move. preloadStrategy is deleted because modulepreload is now supported everywhere, prerender.origin becomes paths.origin, and csrf.checkOrigin becomes csrf.trustedOrigins [8].
The import change is where the hours go. #lib is a Node subpath import that Vite and TypeScript resolve natively, so it follows Node's rules instead of a SvelteKit-generated alias [9]. Node and TypeScript require subpath imports to be unambiguous. An import of #lib/foo fails and has to be written #lib/foo.ts or #lib/foo/index.ts [10]. According to the post, the migration script handles most of the rename, but the author tells readers to check the extension rule before trusting the script's output [9][10].
The last two items are smaller. tsconfig.json now extends $app/tsconfig, a generated file in node_modules, in place of ./.svelte-kit/tsconfig.json [11]. The release-candidate post says most custom compilerOptions can likely be deleted, and that include and exclude should be set explicitly, with exclude covering the service worker [11]. That service worker also loses the $service-worker module and imports from $app/env, $app/paths and the new $app/manifest instead [12].
What to watch
- Whether the latest SvelteKit 2.x release is documented as running on Vite 8 and vite-plugin-svelte 7, the fact that decides if the toolchain can ship first.
- First production migration reports on how much of the $lib-to-#lib rewrite the migration script completes, including missing file extensions.
- TypeScript 6 support from the plugins that kept teams pinned to TypeScript 5.