Back

A Beginner's Guide to Remote Functions in SvelteKit

A Beginner's Guide to Remote Functions in SvelteKit

You’ve built SvelteKit apps with +server.ts endpoints and form actions. They work, but you’re writing boilerplate: parsing request bodies, validating inputs manually, and maintaining separate type definitions for client and server. SvelteKit Remote Functions offer a different approach—type-safe server calls without the ceremony of traditional API endpoints.

This guide explains what remote functions are, when to use each type, and the trade-offs you should understand before adopting them.

Key Takeaways

  • Remote functions compile server-side code into HTTP endpoints with auto-generated fetch wrappers, providing end-to-end type safety without manual API route maintenance.
  • Four function types serve distinct purposes: query for data fetching, form for progressively enhanced submissions, command for JavaScript-dependent mutations, and prerender for build-time static data.
  • Every remote function becomes a publicly accessible endpoint, making input validation with Standard Schema libraries like Zod or Valibot essential for security.
  • Remote functions require explicit opt-in and remain experimental, so expect API changes and keep SvelteKit updated to address potential vulnerabilities.

What Are SvelteKit Remote Functions?

Remote functions let you write server-side code that clients call like regular functions. Behind the scenes, SvelteKit compiles these into HTTP endpoints and generates fetch wrappers for the client. You get end-to-end type safety without building or maintaining traditional API routes.

Think of it as SvelteKit handling the plumbing between your frontend and backend. You write a function in a .remote.ts file, and SvelteKit handles serialization, endpoint generation, and type inference.

If you want the official reference, this feature is documented in the SvelteKit docs under Remote Functions: https://kit.svelte.dev/docs/remote-functions

Enabling the Experimental Feature

Remote functions require explicit opt-in via kit.experimental.remoteFunctions in your svelte.config.js:

const config = {
  kit: {
    experimental: {
      remoteFunctions: true
    }
  }
};

export default config;

If you want to use await directly in Svelte components, you’ll also need Svelte’s experimental async support enabled separately. This isn’t required—remote functions work without it—but it simplifies component code.

The Four Types of SvelteKit Server Functions

Remote functions come in four flavors, each designed for specific use cases.

Query: Fetching Dynamic Data

Use query when reading data from databases, APIs, or any server resource. Queries can run during component render and are deduplicated and batched within the same render lifecycle.

import { query } from '$app/server';
import { db } from '$lib/db';
import { posts } from '$lib/schema';

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

For performance-critical scenarios, query.batch groups multiple simultaneous calls into a single request—solving the n+1 problem without manual optimization.

Form: Data Mutations with Progressive Enhancement

The form function handles user input submission. Its key advantage is progressive enhancement. Forms work without JavaScript, falling back to traditional submission when needed.

Spread the returned object onto your <form> element, and SvelteKit handles both enhanced and non-enhanced submissions automatically.

Command: Flexible Mutations

command works like form but isn’t tied to form elements. Use it for button clicks, drag-and-drop actions, or any mutation triggered outside a form context.

Unlike forms, commands require JavaScript. Choose form when progressive enhancement matters. Choose command when you need flexibility.

Prerender: Static Data at Build Time

prerender fetches data during build, not at runtime. The results are cached at build time and served via the platform cache or CDN. Use this for configuration, CMS content that changes only on deployment, or any data that doesn’t need real-time updates.

Important constraint: you cannot use query on fully prerendered pages, since queries are inherently dynamic.

Security: Every Remote Function Is a Public Endpoint

This is critical to understand: every remote function becomes an HTTP endpoint anyone can call. Input validation isn’t optional—it’s essential.

SvelteKit expects you to validate arguments using Standard Schema libraries like Zod or Valibot (the “Standard Schema” initiative is documented at https://standardschema.dev):

import { query } from '$app/server';
import * as v from 'valibot';
import { db } from '$lib/db';
import { posts } from '$lib/schema';

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

export const getPost = query(Params, async ({ slug }) => {
  return await db.select().from(posts).where(eq(posts.slug, slug));
});

Without validation, attackers can send arbitrary data to your endpoints. SvelteKit typically returns 400-level errors for validation failures, avoiding information leakage.

Keep SvelteKit Updated

Past versions had security vulnerabilities affecting remote functions, including DoS issues. Stay current with releases, especially while the feature remains experimental (as of SvelteKit 2.x).

Trade-offs to Consider

Remote functions reduce boilerplate but aren’t magic. Consider these constraints:

  • File location matters: .remote.ts files go anywhere in src except src/lib/server
  • Prerender caching: Browser and CDN caching means stale data until redeployment
  • Experimental status: APIs may change and bugs are expected

Remote functions work best when you want type-safe client-server communication without maintaining separate endpoint definitions. They’re not a replacement for every +server.ts file—complex authentication flows or third-party webhook handlers might still warrant traditional endpoints.

When to Use Each Function Type

ScenarioFunction Type
Fetching database recordsquery
Form submission with fallbackform
Button-triggered actionscommand
CMS content, site configprerender

Conclusion

SvelteKit Remote Functions simplify the boundary between client and server code. They eliminate manual endpoint maintenance while providing built-in validation and type safety. Start with query for data fetching, add form for user input, and reach for command or prerender when those specific patterns fit your needs.

The feature is experimental—expect changes. But for SvelteKit developers tired of endpoint boilerplate, remote functions offer a compelling alternative worth exploring.

FAQs

Yes, remote functions and traditional endpoints coexist without conflict. You can migrate incrementally, converting endpoints one at a time. Many projects keep complex authentication or webhook handlers as traditional endpoints while using remote functions for simpler data operations.

Remote functions don't include built-in auth. You access the request context through SvelteKit's standard mechanisms and implement authorization checks within each function. Validate user sessions and permissions at the start of any function that requires protection, just as you would with traditional endpoints.

Unhandled errors return a 500 response to the client. SvelteKit sanitizes error messages in production to prevent leaking sensitive information. For controlled error handling, throw redirect or error objects from @sveltejs/kit, which SvelteKit processes appropriately on the client side.

Remote functions work with any adapter that supports server-side rendering. They compile to standard HTTP endpoints, so platforms like Vercel, Netlify, and Cloudflare Workers handle them normally. Prerender functions work everywhere since they execute at build time only.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay