mcpField
S
sveltekit-remote-functions

sveltekit-remote-functions

github.com/spences10Development1686 installsUpdated 16w ago
Repository

About sveltekit-remote-functions

sveltekit-remote-functions is a development skill covering SvelteKit's experimental remote functions for developers building server-backed applications. It explains function choices, setup, validation, live queries, forms, and current implementation rules.

Key features

  1. 01Explains query, command, form, and prerender functions
  2. 02Covers live and batched queries
  3. 03Describes input validation and serialization constraints
  4. 04Provides setup guidance for the Vite plugin
  5. 05Documents current behaviors and pitfalls

Use cases

  1. 01Choose a remote function for a data operation
  2. 02Add validated server-side reads or mutations
  3. 03Build live data views or progressive forms
  4. 04Check implementation details against current guidance

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/spences10/skills --skill sveltekit-remote-functions

After installing, type/sveltekit-remote-functionsin Claude Code to confirm it loaded.

Bundled filesreferences/remote-functions.md

Details

From the project README

SvelteKit Remote Functions

Current Status

Remote functions are experimental in SvelteKit 2.58. Prefer enabling them in vite.config.ts via the SvelteKit Vite plugin:

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
	plugins: [
		sveltekit({
			experimental: { remoteFunctions: true },
			compilerOptions: { experimental: { async: true } } // only for await in components
		})
	]
});

Quick Start

File naming: export remote functions from *.remote.ts or *.remote.js. Remote files can live anywhere under src except src/lib/server.

Which function?

  • Dynamic reads → query()
  • Realtime server streams → query.live()
  • Progressive forms → form()
  • Event-handler mutations → command()
  • Build-time/static reads → prerender()

Example

// posts.remote.ts
import { command, query, requested } from "$app/server";
import * as v from "valibot";

export const getPosts = query(
	v.object({ tag: v.optional(v.string()) }),
	async (filter) => {
		return db.posts.find(filter);
	},
);

export const createPost = command(
	v.object({ title: v.string() }),
	async (data) => {
		await db.posts.create(data);

		for (const { query } of requested(getPosts, 5)) {
			void query.refresh();
		}
	},
);

Client:

<script lang="ts">
	import { createPost, getPosts } from './posts.remote';

	const posts = $derived(await getPosts({ tag: 'svelte' }));
</script>

<button onclick={() => createPost({ title: 'New' }).updates(getPosts)}>
	Create
</button>

Current Rules

  • svelte.config.js still works in Kit 2, but Kit 3 will read Kit config from the Vite plugin instead.
  • Remote functions always run on the server, even when called from the browser.
  • Args/returns use devalue; avoid functions, class instances, symbols, circular refs, and RegExp.
  • Validate exposed inputs with Standard Schema (valibot, zod, arktype, etc.) or use .unchecked/'unchecked' deliberately.
  • query.batch() batches calls from the same macrotask to solve n+1 reads.
  • query.live() returns an async iterable; SSR uses the first yield, clients stay connected while rendered.
  • Prefer event-driven live queries over polling when a mutation can notify listeners (Promise.withResolvers()/pubsub).
  • Live queries expose connected and reconnect(), but no refresh(); .run() returns Promise<AsyncGenerator<T>>.
  • Do not service-worker-cache live query responses; exclude Cache-Control: no-store streams.
  • form().enhance() submit() returns true when submission is valid/successful and false for validation failures.
  • .updates() is client-requested; server handlers must opt in with requested(queryFn, limit).
  • requested() now yields { arg, query }; call query.refresh()/query.set(...) on the bound instance.
  • limit is required for requested() to cap client-controlled refresh requests.
  • Inside command/form handlers, use void query.refresh()/void query.set(value); SvelteKit awaits and serializes the updates.
  • For live queries, single-flight mutations can call void live_query.reconnect().
  • Prefer form() over command() where progressive enhancement matters.
  • Use prerender() for data that changes at most once per deployment.
  • Last verified: 2026-06-08

Reference Files

Comments

Markdown supported