Let's look at what actually changes when you upgrade a production app to SvelteKit 3, from configuration moves to new subpath imports.
What you'll learn:
- How to automate your migration using
sv migrate. - Moving your app configuration from
svelte.config.jstovite.config.ts. - Replacing the old
$libalias with standard package subpath imports. - Setting up the new tooling without breaking your build pipeline.
Automated Migration With The CLI
SvelteKit 3 ships with a robust migration tool. Instead of manually updating boilerplate across dozens of files, you can let the CLI handle the heavy lifting.
Run the migration command in your project root:
npx sv migrate sveltekit-3 --tasks all --confirm
Speed note: If you use an AI coding assistant, point it at the generated
TODOlist. It handles repetitive markup updates much faster than a manual find-and-replace.
Moving Config to Vite
In SvelteKit 3, configuration has a cleaner home. We've moved framework settings out of svelte.config.js and consolidated them directly into vite.config.ts.
Here is what your updated setup looks like:
// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()],
server: {
port: 3000
}
});
Keep your Svelte compiler options inside the svelte block of your Vite plugin config if you need custom preprocessors.
Adopting Standard Subpath Imports
The old $lib alias is gone, replaced by standard package subpath imports. This brings SvelteKit in line with modern Node.js module resolution standards.
Update your package.json to define the subpath:
{
"name": "my-app",
"imports": {
"#lib/*": "./src/lib/*"
}
}
Now import your modules using the hash prefix instead of the dollar sign:
<script lang="ts">
// Old: import Button from '$lib/components/Button.svelte';
import Button from '#lib/components/Button.svelte';
</script>
<Button text="Click me" />
Gotcha: TypeScript might complain about module resolution until you run
npx vite buildor restart your language server to regenerate the ambient types.
Cleaner Service Workers and Environment Variables
Boilerplate in service workers is significantly reduced in version 3. Setting up offline caching requires fewer lifecycle hooks and less manual registration logic.
Here is a minimal service worker registration pattern:
// src/service-worker.ts
/// <reference types="@sveltejs/kit" />
/// <reference no-default-lib="true"/>
/// <reference types="lib.webworker.d.ts" />
import { build, files, version } from '$service-worker';
const CACHE = `cache-${version}`;
const ASSETS = [...build, ...files];
self.addEventListener('install', (event) => {
async function addFilesToCache() {
const cache = await caches.open(CACHE);
await cache.addAll(ASSETS);
}
event.waitUntil(addFilesToCache());
});
Environment variables are also tightened up. You get better type inference out of the box without needing custom ambient declarations for every public or private secret.
Summary and Next Steps
SvelteKit 3 removes friction, cleans up old configuration patterns, and aligns the framework closer to native ESM standards.
Next steps:
- Run
npx sv migrate sveltekit-3on a staging branch and check your bundle output. - Refactor your component imports to use
#lib/*subpaths. - Keep an eye out for experimental remote functions as async Svelte matures.