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:
npx sv@latest migrate sveltekit-3
Speed Note: The migration tool handles most boilerplate updates, but check your custom
vite.config.tsplugins 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:
// 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:
// 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-nodenow 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:
npx sv add drizzle
Initialize your database client using Node's native module:
// 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-3on a staging branch, audit your server mutation endpoints for unhandled refresh payloads, and verify your production adapter target settings.