SvelteKit 3 reaches release candidate and moves configuration to Vite
The new release candidate eliminates svelte.config.js, requires Vite 8, and replaces the $lib alias with #lib, based on Node's native imports. A migration CLI automates much of the transition.
RC marks the final stretch before the stable release
The Svelte team moved SvelteKit 3 to the release candidate phase on September 30, according to a report by InfoQ. The team describes the release not as one packed with new features, but as an opportunity to prune legacy code and pave the way for the framework's evolution. If testing goes well, the stable release should ship without any further breaking changes.
This means that anyone testing the RC today is, in practice, validating what will become the final SvelteKit 3. For teams maintaining SvelteKit applications in production, now is the time to run their test suite against the RC before any breaking change arrives unannounced in the stable release.
Configuration moves out of svelte.config.js and into Vite
The most visible change is where the project keeps its configuration. svelte.config.js, which had existed since SvelteKit 2, disappears: configuration now lives inside vite.config.ts, so the Vite plugin can read it synchronously, instead of waiting for an asynchronous step that only began after all of Vite's own configuration finished resolving.
The project's reference documentation notes that configuring via Vite had already been possible since version 2.62 - the RC simply closes out a transition that was already underway. Those who had already migrated their configuration in that earlier version shouldn't feel any impact now; those still on the old model need to move the file before upgrading.
$lib becomes #lib: the change that split opinions
The most debated part of the RC is the retirement of the $lib alias, replaced by #lib. The swap relies on Node's native subpath imports, declared in package.json, instead of a SvelteKit-specific path that Vite and TypeScript had to coordinate manually. In practice, $lib/foo now needs to become #lib/foo.js - with an explicit file extension.
On Reddit, a developer complained about the inconsistency created by the change:
I hate the $lib -> #lib change, it now makes it inconsistent with other things like $app. Hopefully it's not enforced to be #lib and we can just use whatever alias we want
Developer on Reddit, in a thread about SvelteKit 3
Another user initially replied in disagreement, but changed their mind after understanding the logic behind the decision:
Yeah what's the logic in that? Edit: oh nvm it's a great change. They're moving it to the native package.json alias definition. This means you can use the alias in lib/server stuff that you might want to run without sveltekit too.
Developer on Reddit, replying to the previous comment
The technical argument behind the change is that #lib, being a native Node alias, works in any context - including server modules that run outside of SvelteKit, something $lib didn't allow, since it depended on the framework itself to resolve the path.
In the original GitHub issue that discussed the decision, maintainer Rich Harris was direct about the trade-off: he said he'd love for everyone to use nodenext, but acknowledged that developers might revolt against imports without a file extension. For those who disagree with the requirement, the way out he pointed to is simple: create your own alias.
Migration has a ready-made CLI, but demands attention to detail
For those who already have an application in production, the Svelte team published a migration guide that points to a CLI command:
npx sv@next migrate sveltekit-3 --tasks all --confirmThe command automates much of the transition, but two points require manual review: every reference to $lib in the code - imports, custom aliases in internal libraries, editor configuration - needs to be rewritten to #lib with a file extension, and the project's tsconfig.json now extends $app/tsconfig instead of the file previously generated inside .svelte-kit. Teams with large codebases should run the automated migration and then manually hunt down the cases the script doesn't cover, such as dynamic imports or paths built at runtime.
Other changes: errors, routes, and the engine under the hood
SvelteKit 3 now requires Svelte 5, which unlocks a rework of error handling: +error.svelte components render on both load failures and rendering failures, every error goes through handleError, and stack traces gain sourcemaps - which should make debugging in production less painful. Service workers now import from $app/env, $app/paths, and a new $app/manifest module. Explicit environment variables leave experimental status and gain optional validation via Standard Schema.
Shallow routing also gets a new API: pushState is out, goto with the shallow: true option is in. Under the hood, the framework now requires Vite 8 and its Rolldown bundler for faster builds - but the Svelte team decided not to adopt FetchableDevEnvironment, arguing that the proposal forces frameworks to absorb too much complexity.
What's still left out
The so-called remote functions, a type-safe client-server RPC approach that echoes React's Server Actions and Next.js's server functions, remain behind an experimental flag. The team itself acknowledges that, compared to this approach, the current load and actions functions feel somewhat clunky.
For those building with SvelteKit in Brazil, the practical takeaway is to run the RC in a separate branch, test the migration CLI before touching production, and map out where $lib appears in the codebase before the stable release removes the compatibility path for good. SvelteKit has been Svelte's official application framework since the 1.0 release in late 2022, and remains the standard way to build apps with the Svelte compiler, facing competitors like Next.js and Remix.
Translated from the Brazilian Portuguese original · Read the original
AI Agents Refactor 300,000 Lines in Three Weeks, But Experts Split on What It Proves
A CodeScene case study shows agents refactoring 300,000 lines of C for $4,000 in three weeks. Practitioners agree on the numbers, but disagree on what they actually prove.