NewsJavaScript

SvelteKit 3 RC: Remote Functions Replace Load Functions

Split-screen diagram showing SvelteKit 2 load functions on the left and SvelteKit 3 remote functions on the right, illustrating the architectural shift in SvelteKit 3 RC

SvelteKit 3 Release Candidate landed August 13 and jumped to 704 points on Hacker News this week. The headline feature — Remote Functions — is a fundamental rethink of how components talk to servers, and it makes the existing load function pattern look like scaffolding you hired accidentally. There are also breaking changes that will touch every SvelteKit 2 codebase. The stable release is close. Here is what matters.

Remote Functions: Server Calls Without the Plumbing

The problem with load functions has always been their shape. They live on routes, they run top-down, and they require a separate file for every page that needs server data. That is fine for simple cases and increasingly irritating for complex ones. Remote Functions flip the model: you write server code in a .remote.ts file, and any component in your project can call it like a regular async function. SvelteKit handles the HTTP endpoint, the client wrapper, and the TypeScript types automatically.

There are four types. query() fetches data and can run during component render — it supports request batching to avoid the n+1 problem. command() handles mutations that require JavaScript. form() handles mutations with progressive enhancement baked in, meaning the form works without JavaScript. prerender() caches data at build time for static pages.

// src/lib/posts.remote.ts
import { query } from '$app/server';
import * as v from 'valibot';

const Params = v.object({ slug: v.string() });

export const getPost = query(Params, async ({ slug }) => {
  return db.posts.findOne({ slug });
});
<!-- +page.svelte — no load function, no route file -->
<script>
  import { getPost } from '#lib/posts.remote';
  const post = getPost({ slug: $page.params.slug });
</script>

{#await post}
  <p>Loading...</p>
{:then data}
  <Article {data} />
{/await}

One point that cannot be glossed over: every remote function becomes a public HTTP endpoint. Input validation via a Standard Schema library — Zod, Valibot, or ArkType — is not optional. If you skip it, you have an unvalidated API surface exposed to the internet. Remote functions are still behind an experimental flag (kit.experimental.remoteFunctions: true). The API works and the team considers it directionally correct, but production use before stable is a judgment call.

Why This Matters for the Next.js Debate

SvelteKit 3 arrives as the gap between it and Next.js is actually narrowing. The Register framed the RC as SvelteKit “putting heat on Next.js with a radical approach to RPCs,” and the numbers are concrete. A recent benchmark found SvelteKit’s SSR payload three times smaller than Next.js for an equivalent product page. Server load testing showed SvelteKit handling 1,200 requests per second against Next.js 16’s 850 — a 41 percent throughput advantage. The underlying reason is architectural: Svelte compiles to vanilla JavaScript at build time, shipping no runtime to the client.

Remote functions sharpen the contrast around server communication. Next.js Server Functions — introduced with the App Router — were designed primarily for mutations. Reading data cleanly requires mixing server components with server functions in ways that add cognitive overhead. SvelteKit’s query() and command() handle reads and writes symmetrically inside the same abstraction, with the same file convention, and no routing boilerplate.

Breaking Changes: What Every SvelteKit 2 Project Faces

Remote Functions are the good news. The migration cost is the honest part of this story.

Configuration moves to vite.config.ts. The kit: {} block in svelte.config.js moves into the sveltekit() plugin call in vite.config.ts. The team describes it as copy-paste, and the effort is genuinely low — but it is required, and several config options were removed or renamed in the process.

$lib becomes #lib. This generates the most discussion. The change aligns with Node’s native subpath imports via the package.json imports field. Practically, it means updating imports throughout your codebase, and file extensions are now required: #lib/foo.ts not #lib/foo. The automated migration tool handles the bulk replacement.

Navigation and error APIs are renamed. pushState and replaceState become goto() with a shallow: true option. invalidateAll becomes refreshAll — note that refreshAll does not reset page.state, which is a behavioral difference worth testing. The error() function signature changes: the second argument must now be a string message, with additional properties in a third argument.

Minimum versions to check before migrating: Node v22.17+, TypeScript v6+, Svelte v5.56.4+, Vite v8.0.12+.

How to Migrate

Run the automated migration tool first:

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

It handles the config move, most alias replacements, and the navigation API renames. It generates a TODO list for manual changes: file extension updates on #lib imports, TypeScript config updates (tsconfig.json now extends $app/tsconfig), CSRF configuration, and param matcher consolidation.

Full migration documentation is at next.svelte.dev. The official RC announcement has the complete feature overview. For a deeper look at Remote Functions, the OpenReplay guide covers all four types with examples.

Should You Migrate Now?

Not for production, not yet. Remote Functions carry an experimental flag and the API can still change. However, the RC is stable enough to run in development, and getting familiar with the migration path before stable drops is time well spent. The breaking changes are real but bounded — teams that migrated multiple SvelteKit projects to Vite 8 did it in a day.

The direction is clear: Remote Functions are where SvelteKit is going, and the load function pattern is on its way out. The performance numbers against Next.js give the Svelte team something concrete to argue with. If you are evaluating frameworks for a new project, this RC narrows the reasons to default to Next.js.

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