---
title: "SvelteKit 3: Breaking Changes and Migration Guide"
description: "SvelteKit 3 moves config into vite.config.ts, renames $lib to #lib, and reworks env vars, service workers, and error handling. Here is how to migrate."
slug: "sveltekit-3-breaking-changes-and-migration-guide"
published: true
read_time: 7
created_at: "2026-10-02 14:04:33.021 +0000 UTC"
updated_at: "2026-10-02 14:04:33.025 +0000 UTC"
author: "Typen"
author_url: "https://typen.blog/@typen"
tags:
  - "Featured"
  - "Open Source"
  - "Frontend"
---

# SvelteKit 3: Breaking Changes and Migration Guide

SvelteKit 3 moves config into vite.config.ts, renames $lib to #lib, and reworks env vars, service workers, and error handling. Here is how to migrate.

![https://media.typen.blog/img/id/01a0fcee-539a-70ce-af80-4da3ccc89564](trendbot-3074229089.webp)

SvelteKit 3.0 is now available, and the Svelte team describes it as the same framework with a little more polish, a little more type safety, and a little less junk. For teams already running SvelteKit 2, the upgrade is deliberately incremental: most of the mental model, routing conventions, and file layout stay the same. What changes is a set of breaking changes around configuration, module resolution, environment variables, service workers, and error handling.

This article walks through what is new, what breaks, and how to plan a migration.

## The migration command

The Svelte team has shipped a dedicated migration path through the `sv` CLI. The command is:

```bash
npx sv migrate sveltekit-3 --tasks all --confirm
```

According to the announcement, this will automatically migrate as much of your codebase as possible and generate a TODO list for everything else. That TODO list matters: automated codemods handle mechanical renames and config moves well, but they cannot reason about your application's specific use of environment variables, service workers, or error boundaries. Treat the migration command as the start of the work, not the end.

To create a brand new app rather than migrate an existing one, the command is:

```bash
npx sv create my-new-app
```

## Breaking change: configuration moves to vite.config.ts

The most visible change is that SvelteKit configuration now lives in `vite.config.ts` instead of `svelte.config.js`. This consolidates two files that were always conceptually related. Vite is the underlying build tool for SvelteKit, and having adapter, alias, and preprocessor configuration split across two files was a long-standing source of confusion.

For migration, this mostly means moving the contents of your `svelte.config.js` into the Vite config and deleting the old file. The practical consequence is that anything importing or reading `svelte.config.js` — custom scripts, CI checks, tooling that parses the file — needs to be updated. If your project has any bespoke build automation that touches that file, audit it before running the migration.

## Breaking change: $lib becomes #lib

The `$lib` alias is now `#lib`. This is not an arbitrary rename: it aligns SvelteKit with standard Node.js subpath imports, which use the `#` prefix and are declared in `package.json`. Using a standard mechanism means better interoperability with the broader JavaScript tooling ecosystem, and it removes a SvelteKit-specific convention in favor of one the runtime already understands.

The migration is largely a find-and-replace across import statements, which the automated migration should handle. The risk is in dynamic or generated imports, string references in configuration, and documentation or code snippets that reference `$lib` as a literal string. Those will not be caught by a naive codemod.

## Environment variables: more powerful, easier to use

Environment variable handling has been reworked. The announcement describes the new system as more powerful and easier to use, and the docs now present `$app/env/private` and `$app/env/public` as the primary modules, with `$env/dynamic/private`, `$env/dynamic/public`, `$env/static/private`, and `$env/static/public` listed under a Legacy section.

That legacy listing is the key migration signal. If your codebase imports from `$env/*`, you have work to do. The old static/dynamic split forced developers to choose between build-time inlining and runtime access, and getting it wrong had real consequences — leaking secrets into client bundles, or breaking deployments where variables are only available at runtime. The new modules appear to unify that model.

Because environment variables often encode deployment topology, this is the area where you should be most careful. Verify that private variables remain server-only after migration, and test on your actual hosting adapter rather than only in local development.

## Service workers with less boilerplate

Service workers in SvelteKit have historically required a fair amount of manual wiring. Version 3 reduces that boilerplate. The docs now reference `$app/service-worker` as the current module, with the older `$service-worker` moved to the Legacy section.

If you maintain a custom service worker — for offline support, caching strategies, or push notifications — expect to update your imports and possibly your registration logic. Service worker bugs are notoriously hard to reproduce, so test cache invalidation and update flows explicitly rather than assuming the migration preserved behavior.

## Improved error handling

Error handling is described as improved across the board. Svelte itself has a `<svelte:boundary>` special element for handling errors in component trees, and SvelteKit's error pages and fallback error mechanisms are documented in the tutorial. The migration guide is the authoritative source for exactly what changed, but the general direction is more predictable, more granular error handling at both the component and framework level.

For applications that rely on custom `+error.svelte` pages or `handleError` hooks, review those implementations after upgrading. Improved error handling often means the framework now catches cases it previously let through, which can surface latent bugs as new error states.

## Remote functions are not ready

The announcement is explicit: remote functions are not ready yet, but they are the team's top priority. Remote functions are a set of utilities for secure, efficient, type-safe client-server communication — conceptually similar to ideas seen in other frameworks, though the Svelte team expects developers to prefer this implementation.

Using them requires Async Svelte, which currently requires an `experimental` flag. If you are evaluating SvelteKit 3 for a new project and remote functions are central to your architecture, plan around the experimental status. Do not build production-critical paths on an experimental flag unless you can absorb breaking changes.

## Migration strategy

A few practical recommendations for teams planning the upgrade:

1. **Upgrade SvelteKit and Svelte together.** Async Svelte and the new error handling are Svelte-level features that SvelteKit 3 builds on. Check the migration guide for version requirements before starting.
2. **Run the migration command on a branch, then review the diff carefully.** The generated TODO list is a checklist, not a formality.
3. **Grep for the renamed identifiers.** Search for `$lib`, `$env/`, `$service-worker`, and `svelte.config.js` across your repo, including docs, scripts, and CI configuration.
4. **Test environment variable behavior on your real adapter.** This is the highest-risk change for deployed applications.
5. **Exercise service worker update flows.** Verify that clients pick up new service worker versions and that caches invalidate correctly.
6. **Review error boundaries and error pages.** Improved error handling may change which component or hook receives an error.

## Tradeoffs

The consolidation of configuration into `vite.config.ts` and the switch to standard subpath imports are both moves toward fewer SvelteKit-specific conventions. That is good for interoperability and for developers moving between frameworks, but it does mean churn in every existing project. The rename from `$lib` to `#lib` in particular touches nearly every file in a typical codebase, which makes the diff noisy even though the change is mechanical.

The environment variable rework is the change most likely to have real production consequences. A unified model is easier to reason about, but any migration that touches secret handling deserves careful verification. The legacy modules remain documented, which suggests a transition period rather than an immediate cliff — but relying on legacy imports long term is a maintenance liability.

Finally, the headline feature that many developers are waiting for — remote functions — is not in this release. SvelteKit 3 is a consolidation release: polish, type safety, and cleanup, with the more ambitious client-server story still ahead.

## Getting started

The official migration guide and the release candidate announcement are the authoritative references. For new projects, `npx sv create` scaffolds a SvelteKit 3 app with the new conventions already in place, which is a reasonable way to see the target state before migrating an existing codebase.

