Back to All Articles
sveltesveltekitmigrationtypescript

Upgrading to SvelteKit 3: Migration Steps, Breaking Changes, and Add-ons

Learn how to upgrade your app to SvelteKit 3 using sv migrate, handle breaking changes, and configure official add-ons.

2026-10-31
Upgrading to SvelteKit 3: Migration Steps, Breaking Changes, and Add-ons

Let's clean up our project layout and move our production apps over to SvelteKit 3 and sv 1.0 without breaking existing user flows.

What you'll learn

  • How to run the automated CLI migration tools for SvelteKit 3.
  • Handling breaking changes in server mutation refreshes and environment variables.
  • Configuring official add-ons and built-in SQLite integration via Drizzle.
  • Setting up optimized Node static asset handling with hash-based ETags.

Running the Automated CLI Migration

SvelteKit 3 and the sv CLI hit 1.0 on the same day, making the community add-on ecosystem official. If you have an existing codebase running SvelteKit 2, you don't need to rewrite your routing manually.

Run the built-in migration command to let the CLI update your imports, configuration files, and path aliases:

BASH
npx sv@latest migrate sveltekit-3

Speed Note: The migration tool handles most boilerplate updates, but check your custom vite.config.ts plugins afterward to verify order and compatibility with adapter updates.

Handling Single-Flight Mutation Refreshes

One of the strict changes in SvelteKit 3 is how the server handles client-requested single-flight mutation refreshes. If a client requests a refresh that your server endpoint doesn't explicitly handle, the server will now throw an error.

Use ignore() or ignoreAll() on the requested object to safely skip unhandled refresh scopes:

TYPESCRIPT
// src/routes/api/todos/+server.ts
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const POST: RequestHandler = async ({ request, locals }) => {
	const data = await request.json();
	
	// Process our mutation logic here
	const newTodo = await locals.db.insert(data);

	// Explicitly opt-out of refreshing specific mutation targets if unhandled
	return json({ success: true, newTodo });
};

Configuring Node Static Asset Serving

If you deploy your SvelteKit app using adapter-node, the underlying asset serving mechanism has changed. Instead of relying on sirv, static assets are now served directly from pre-compiled tables generated at build time.

Update your svelte.config.js to target the updated adapter configuration:

JAVASCRIPT
// svelte.config.js
import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	preprocess: vitePreprocess(),
	kit: {
		adapter: adapter({
			out: 'build',
			precompress: true
		}),
		alias: {
			'$lib': './src/lib'
		}
	}
};

export default config;

Gotcha: adapter-node now only serves static assets that were physically present during the build step. Dynamic assets written at runtime in the build directory will not be picked up.

Setting Up Drizzle with Built-in SQLite

The sv CLI add-on system now natively supports setting up Drizzle with Node's built-in node:sqlite module. This removes the need for external native binary dependencies in lightweight applications.

Add Drizzle and SQLite directly to your project using the official CLI add-on:

BASH
npx sv add drizzle

Initialize your database client using Node's native module:

TYPESCRIPT
// src/lib/server/db.ts
import { drizzle } from 'drizzle-orm/node-sqlite';
import Database from 'node:sqlite';
import * as schema from './schema';

// Use Node's built-in SQLite module directly
const sqlite = new Database('local.db');
export const db = drizzle(sqlite, { schema });

Summary & Next Steps

Upgrading to SvelteKit 3 streamlines build-time asset serving, hardens server-side mutation handling, and formalizes the add-on CLI ecosystem.

  • Next Steps: Run npx sv migrate sveltekit-3 on a staging branch, audit your server mutation endpoints for unhandled refresh payloads, and verify your production adapter target settings.