NewsJavaScriptDeveloper ToolsWeb Development

SvelteKit 3 RC: Remote Functions and the $lib Break

SvelteKit 3 release candidate featuring remote functions and the dollar-lib to hash-lib migration
SvelteKit 3 RC introduces remote functions and breaks the dollar-lib alias

SvelteKit 3 is in release candidate. Two things matter: remote functions — an end-to-end typed RPC system that eliminates manual API routes — and a $lib alias removal that will break every existing SvelteKit 2 project’s imports the moment you upgrade. The Svelte team is betting big on both, and whether you upgrade now or wait for stable, you need to understand what’s changing.

Remote Functions: RPC Without the Boilerplate

The most significant new feature is remote functions, elevated from experimental status in SvelteKit 2.27 to first-class citizen in SvelteKit 3. The concept is straightforward: create a .remote.ts file anywhere in src/, export functions in one of four shapes, and import them from your components as if they were local. SvelteKit generates the HTTP endpoint and fetch wrappers for you.

The four shapes cover every data pattern: query for reading dynamic server data, form for progressively enhanced form submissions, command for JavaScript-dependent mutations (like buttons and drag-to-reorder), and prerender for build-time static data cached at the CDN edge.

A basic query replaces your +page.server.ts load function entirely:

// src/posts.remote.ts
import { query } from '@sveltejs/kit/remote';
import { db } from '#lib/db.js';

export const getPosts = query(async () => {
  return db.posts.findMany();
});

Import it in your component and call it. No fetch, no manual typing, no endpoint to maintain. The Svelte team’s own take: “Remote functions make everything else look a bit clunky, including SvelteKit’s load functions and actions.”

The obvious comparison is Next.js Server Actions, but it doesn’t quite hold. Server Actions are optimized for mutations, not fetching. SvelteKit remote functions cover both reads and writes with end-to-end type safety — a genuinely different model. The Register put it bluntly: SvelteKit 3 is putting heat on Next.js with a radical approach to RPCs.

One important caveat: remote functions are still seeing breaking changes between RC minor versions. Adopt them on new features only — do not rewrite existing load functions until stable lands.

The $lib Break: Every Import in Your Project

This is the one that will sting. SvelteKit 3 drops the $lib alias entirely, replacing it with #lib — a Node subpath import declared in your package.json:

// package.json
{
  "imports": {
    "#lib/*": "./src/lib/*"
  }
}

Every import that reads from '$lib/...' becomes from '#lib/...', and you must include explicit file extensions:

// Before
import { db } from '$lib/db';

// After
import { db } from '#lib/db.js';

The reason is principled: #lib uses Node’s built-in subpath import resolution, which Vite and TypeScript handle natively without custom alias logic. The result is a cleaner setup — but it will touch every file in your codebase. The automated migration handles this, but you need to audit the output.

The Other Breaks: Config, Env, Routing

Three more changes are worth knowing before you run the migration command.

Config consolidation: svelte.config.js is gone. SvelteKit 3 fails the build if the file exists. Everything moves into the sveltekit() plugin in vite.config.ts:

// vite.config.ts — the only config file you need
import { sveltekit } from '@sveltejs/kit/vite';
import adapter from '@sveltejs/adapter-auto';

export default {
  plugins: [sveltekit({ adapter: adapter() })]
};

Module rename: $app/environment is now $app/env. Small rename, hard error if missed.

Shallow routing: pushState from $app/navigation is gone. Use goto('', { shallow: true, state: { ... } }) instead.

Error handling: All errors — including deliberate error() calls — now route through your handleError hook. The previous behavior (deliberate errors bypassing handleError) is gone. If your handleError does logging, expect more noise until you filter it.

Migration: One Command, One TODO List

The automated migration handles most of this:

npx sv@next migrate sveltekit-3 --tasks all --confirm

It bumps dependencies, rewrites $lib to #lib, renames $app/environment to $app/env, and updates shallow routing calls. What it cannot automate: service worker rewrites (the old $service-worker module is replaced by imports from $app/paths, $app/manifest, and $app/env) and handleError logic adjustments. It generates a TODO list for those. The sv CLI’s new ai-tools add-on can work through that list if you want automated assistance.

For a complete list of changes, the official SvelteKit 3 migration guide lives on next.svelte.dev until stable.

Migrate Now or Wait?

For production applications, wait for stable. The Svelte team says stable is “in the near future” following the RC, with no further planned breaking changes to non-remote-function features. For greenfield projects, starting on the RC is reasonable — the non-remote-functions API is solid.

For remote functions specifically: do not rewrite existing load functions. Adopt them on new features only until stable lands and the API settles.

SvelteKit 3 RC is a real upgrade. The config simplification is overdue, the #lib change is painful but principled, and remote functions — once stable — could meaningfully reshape how full-stack Svelte apps are structured. The full SvelteKit 3 RC announcement is on the Svelte blog. The question isn’t whether to upgrade; it’s when.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:News