SvelteKit 3 hit Release Candidate on August 13. That means one thing for the 13 preview builds that came before it: the breaking changes are locked in. No more surprises. Stable is next, and if your project still runs SvelteKit 2, you have a clean window to migrate on your schedule instead of scrambling when stable forces your hand.
What "Release Candidate" Actually Means Here
This is not another preview release. The Svelte team has committed: from this point, only reviewed bug fixes are allowed before stable. The feature set is done. If you have been watching the @next releases since July, you already know what is coming. If you have been waiting for "the dust to settle" — it has. The RC is that signal.
The Breaking Changes That Will Hit Your Code
Three changes will affect virtually every SvelteKit 2 project. One of them has an automated fix. The other two require understanding what the new model looks like.
1. Config Moves from svelte.config.js to vite.config.js
SvelteKit 3 eliminates svelte.config.js. All project configuration now lives inside the sveltekit() Vite plugin call in vite.config.js. The reasoning is sound: async resolution complexity goes away, and there is one config file to find instead of two.
The migration is mechanical. Copy your exported object into sveltekit({ … }), delete svelte.config.js, and you are done.
// Before: svelte.config.js
import adapter from '@sveltejs/adapter-auto';
export default {
kit: { adapter: adapter() }
};
// After: vite.config.js
import { sveltekit } from '@sveltejs/vite-plugin-svelte';
export default {
plugins: [sveltekit({ adapter: adapter() })]
};
2. $lib Is Gone — Say Hello to #lib
SvelteKit used to auto-generate a $lib alias pointing to your src/lib directory. SvelteKit 3 replaces it with #lib, a standard Node.js subpath import you declare in package.json. Vite and TypeScript resolve it natively — no SvelteKit magic required.
// Before
import { foo } from '$lib/foo';
// After
import { foo } from '#lib/foo.js';
Note the required file extension. Add the following to your package.json:
"imports": {
"#lib": "./src/lib/index.js",
"#lib/*": "./src/lib/*"
}
This looks more disruptive than it is. The migration tool handles the rename across your entire codebase automatically.
3. $env/* Is Deprecated — Explicit Env Vars Are Now Standard
The $env/static/public, $env/dynamic/private, and $app/environment imports are all deprecated in SvelteKit 3, replaced by an explicit environment variable system defined in src/env.ts. You declare what your app needs, whether each variable is public or private, and whether it resolves at build time or runtime. The payoff: proper dead code elimination for build-time vars and type safety enforced at the schema level.
// src/env.ts
import { defineEnvVars } from '@sveltejs/kit/env';
export const variables = defineEnvVars({
PUBLIC_API_URL: { public: true, buildTime: true },
DB_PASSWORD: { public: false, buildTime: false }
});
Import via $app/env/public or $app/env/private instead of the old $env paths. Two more removals worth noting: $app/stores (the page, navigating, and updated stores) is gone, replaced by $app/state using Svelte 5 runes — drop the $ prefix from usage sites. The $service-worker module has also been replaced by $app/manifest and $app/service-worker for properly-typed service worker development.
Run the Migration Tool Before You Do Anything Else
One command handles the majority of the mechanical work:
npx sv@next migrate sveltekit-3 --tasks all --confirm
It relocates your config, renames $lib to #lib across your codebase, and migrates $env references. For anything it cannot automate, it generates a TODO list with @migration annotations so nothing gets missed. The recommended sequence: upgrade to the latest SvelteKit 2.x release first — it surfaces targeted deprecation warnings that make the TODO list shorter. Then run the migration tool. Then test.
Full migration documentation lives at the official SvelteKit 3 migration guide, and the sv migrate CLI reference covers every flag.
Check Your Dependencies Before You Touch Anything
SvelteKit 3 raises the floor across the board. Verify you meet each minimum before starting:
- Node.js v22.17+
- TypeScript v6+
- Svelte v5.56.4+
- Vite v8.0.12+
- @sveltejs/vite-plugin-svelte v7+
The one that will actually slow teams down is Vite 8. It ships with Rolldown as its bundler — a Rust-based replacement for both esbuild and Rollup. Rolldown is significantly faster, but it broke compatibility with older Vite plugins. Audit your plugin list before starting the migration, not after running it and getting an unexpected failure.
What You Get for the Trouble
Past the breaking changes, SvelteKit 3 ships improvements worth having. The new $app/manifest module gives you typed access to app metadata anywhere, including in service workers, which makes offline caching and PWA features substantially less painful. Shallow routing moved from the pushState/replaceState API into goto() with a shallow: true flag, and shallow navigations now properly trigger beforeNavigate handlers. The tracing API is out of experimental — use it without feature flags. Zero-config +error.svelte props mean error pages get their types without extra setup.
The developer satisfaction numbers back this up: SvelteKit consistently pulls 93% satisfaction in State of JavaScript surveys, and that number did not come from a framework that makes migration hell a regular occurrence.
What to Do Right Now
If you are running SvelteKit 2: upgrade to the latest 2.x patch, run the migration command against your codebase, audit the Vite 8 plugin list, and smoke-test against the RC with npm install @sveltejs/kit@next. Do it this week. When stable drops — and it will be weeks, not months — you want the migration already done.
The RC milestone is not a formality. It is the Svelte team saying the work is finished. For once, the framework’s own advice and your team’s schedule are aligned: there is no reason to wait.













