Back to All Articles
sveltesveltekitvitetypescript

Upgrading to SvelteKit 3: Navigating Vite Configs, Subpath Imports, and Breaking Changes

Learn how to migrate your SvelteKit app to version 3, handle the move to vite.config.ts, and adopt standard subpath imports.

2026-11-02
Upgrading to SvelteKit 3: Navigating Vite Configs, Subpath Imports, and Breaking Changes

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.js to vite.config.ts.
  • Replacing the old $lib alias 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:

BASH
npx sv migrate sveltekit-3 --tasks all --confirm

Speed note: If you use an AI coding assistant, point it at the generated TODO list. 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:

TYPESCRIPT
// 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:

JSON
{
	"name": "my-app",
	"imports": {
		"#lib/*": "./src/lib/*"
	}
}

Now import your modules using the hash prefix instead of the dollar sign:

SVELTE
<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 build or 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:

TYPESCRIPT
// 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-3 on 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.