SvelteKit • Core concepts
Remote functions
On this page
- Overview
- query
- Query arguments
- Deduplication
- Refreshing queries
- query.batch
- query.live
- form
- Fields
- Programmatic validation
- Validation
- Getting/setting inputs
- Handling sensitive data
- Returns and redirects
- enhance
- Multiple instances of a form
- Multiple submit buttons
- command
- Single-flight mutations
- Server-driven refreshes
- Reconnecting live queries in mutations
- Client-requested refreshes
- prerender
- Prerender arguments
- Handling validation errors
- Using getRequestEvent
- Redirects
Available since 2.27
Remote functions are a tool for type-safe communication between client and server. They can be called anywhere in your app, but always run on the server, meaning they can safely access server-only modules containing things like environment variables and database clients.
Combined with Svelte’s experimental support for await, it allows you to load and manipulate data directly inside your components.
This feature is currently experimental, meaning it is likely to contain bugs and is subject to change without notice. You must opt in by adding the compilerOptions.experimental.async and kit.experimental.remoteFunctions options in your svelte.config.js:
import type { Config } from '@sveltejs/kit';
const const config: Configconst config: Configconfig: Config = {
Config.kit?: KitConfig | undefinedSvelteKit options.
Config.kit?: KitConfig | undefinedSvelteKit options.
kit: {
KitConfig.experimental?: {
explicitEnvironmentVariables?: boolean;
tracing?: {
server?: boolean;
};
instrumentation?: {
server?: boolean;
};
remoteFunctions?: boolean;
forkPreloads?: boolean;
handleRenderingErrors?: boolean;
} | undefined
Experimental features. Here be dragons. These are not subject to semantic versioning, so breaking changes or removal can happen in any release.
KitConfig.experimental?: {
explicitEnvironmentVariables?: boolean;
tracing?: {
server?: boolean;
};
instrumentation?: {
server?: boolean;
};
remoteFunctions?: boolean;
forkPreloads?: boolean;
handleRenderingErrors?: boolean;
} | undefined
Experimental features. Here be dragons. These are not subject to semantic versioning, so breaking changes or removal can happen in any release.
experimental: {
remoteFunctions?: boolean | undefinedWhether to enable the experimental remote functions feature. This feature is not yet stable and may be changed or removed at any time.
remoteFunctions?: boolean | undefinedWhether to enable the experimental remote functions feature. This feature is not yet stable and may be changed or removed at any time.
remoteFunctions: true
}
},
SvelteConfig.compilerOptions?: Omit<CompileOptions, "filename" | "format" | "generate"> | undefinedThe options to be passed to the Svelte compiler. A few options are set by default,
including dev and css. However, some options are non-configurable, like
filename, format, generate, and cssHash (in dev).
SvelteConfig.compilerOptions?: Omit<CompileOptions, "filename" | "format" | "generate"> | undefinedThe options to be passed to the Svelte compiler. A few options are set by default,
including dev and css. However, some options are non-configurable, like
filename, format, generate, and cssHash (in dev).
compilerOptions: {
experimental?: {
async?: boolean;
} | undefined
Experimental options
experimental?: {
async?: boolean;
} | undefined
Experimental options
experimental: {
async?: boolean | undefinedAllow await keyword in deriveds, template expressions, and the top level of components
async?: boolean | undefinedAllow await keyword in deriveds, template expressions, and the top level of components
async: true
}
}
};
export default const config: Configconst config: Configconfig;/** @type {import('@sveltejs/kit').Config} */
const const config: Configconst config: Configconfig = {
Config.kit?: KitConfig | undefinedSvelteKit options.
Config.kit?: KitConfig | undefinedSvelteKit options.
kit: {
KitConfig.experimental?: {
explicitEnvironmentVariables?: boolean;
tracing?: {
server?: boolean;
};
instrumentation?: {
server?: boolean;
};
remoteFunctions?: boolean;
forkPreloads?: boolean;
handleRenderingErrors?: boolean;
} | undefined
Experimental features. Here be dragons. These are not subject to semantic versioning, so breaking changes or removal can happen in any release.
KitConfig.experimental?: {
explicitEnvironmentVariables?: boolean;
tracing?: {
server?: boolean;
};
instrumentation?: {
server?: boolean;
};
remoteFunctions?: boolean;
forkPreloads?: boolean;
handleRenderingErrors?: boolean;
} | undefined
Experimental features. Here be dragons. These are not subject to semantic versioning, so breaking changes or removal can happen in any release.
experimental: {
remoteFunctions?: boolean | undefinedWhether to enable the experimental remote functions feature. This feature is not yet stable and may be changed or removed at any time.
remoteFunctions?: boolean | undefinedWhether to enable the experimental remote functions feature. This feature is not yet stable and may be changed or removed at any time.
remoteFunctions: true
}
},
SvelteConfig.compilerOptions?: Omit<CompileOptions, "filename" | "format" | "generate"> | undefinedThe options to be passed to the Svelte compiler. A few options are set by default,
including dev and css. However, some options are non-configurable, like
filename, format, generate, and cssHash (in dev).
SvelteConfig.compilerOptions?: Omit<CompileOptions, "filename" | "format" | "generate"> | undefinedThe options to be passed to the Svelte compiler. A few options are set by default,
including dev and css. However, some options are non-configurable, like
filename, format, generate, and cssHash (in dev).
compilerOptions: {
experimental?: {
async?: boolean;
} | undefined
Experimental options
experimental?: {
async?: boolean;
} | undefined
Experimental options
experimental: {
async?: boolean | undefinedAllow await keyword in deriveds, template expressions, and the top level of components
async?: boolean | undefinedAllow await keyword in deriveds, template expressions, and the top level of components
async: true
}
}
};
export default const config: Configconst config: Configconfig;Overview
Remote functions are exported from a .remote.js or .remote.ts file, and come in four flavours: query, form, command and prerender. On the client, the exported functions are transformed to fetch wrappers that invoke their counterparts on the server via a generated HTTP endpoint. Remote files can be placed anywhere in your src directory (except inside the src/lib/server directory), and third party libraries can provide them, too.
query
The query function allows you to read dynamic data from the server.
For static data, consider using
prerenderfunctions instead. Queries cannot be used when the entire page is prerendered (meaningexport const prerender = trueis applied to the page or a parent layout), such as when usingadapter-static.
// @filename: ambient.d.ts
declare module '$lib/server/database' {
export function function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql(strings: TemplateStringsArraystrings: TemplateStringsArraystrings: TemplateStringsArray, ...values: any[]values: any[]values: any[]): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<any[]>;
}
// @filename: index.js
// cut
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query } from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database';
export const const getPosts: RemoteQueryFunction<void, any[]>getPosts = query<any[]>(fn: () => MaybePromise<any[]>): RemoteQueryFunction<void, any[]> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(async () => {
const const posts: any[]posts = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql`
SELECT title, slug
FROM post
ORDER BY published_at
DESC
`;
return const posts: any[]posts;
});Throughout this page, you’ll see imports from fictional modules like
$lib/server/databaseand$lib/server/auth. These are purely for illustrative purposes — you can use whatever database client and auth setup you like.The
db.sqlfunction above is a tagged template function that escapes any interpolated values.
The query returned from getPosts works as a Promise that resolves to posts:
<script lang="ts">
import { getPosts } from './data.remote';
</script>
<h1>Recent posts</h1>
<ul>
{#each await getPosts() as { title, slug }}
<li><a href="/blog/{slug}">{title}</a></li>
{/each}
</ul><script>
import { getPosts } from './data.remote';
</script>
<h1>Recent posts</h1>
<ul>
{#each await getPosts() as { title, slug }}
<li><a href="/blog/{slug}">{title}</a></li>
{/each}
</ul>Until the promise resolves — and if it errors — the nearest <svelte:boundary> will be invoked.
While using await is recommended, as an alternative the query also has loading, error and current properties:
<script lang="ts">
import { getPosts } from './data.remote';
const query = getPosts();
</script>
<h1>Recent posts</h1>
{#if query.error}
<p>oops!</p>
{:else if query.loading}
<p>loading...</p>
{:else}
<ul>
{#each query.current as { title, slug }}
<li><a href="/blog/{slug}">{title}</a></li>
{/each}
</ul>
{/if}<script>
import { getPosts } from './data.remote';
const query = getPosts();
</script>
<h1>Recent posts</h1>
{#if query.error}
<p>oops!</p>
{:else if query.loading}
<p>loading...</p>
{:else}
<ul>
{#each query.current as { title, slug }}
<li><a href="/blog/{slug}">{title}</a></li>
{/each}
</ul>
{/if}For the rest of this document, we’ll use the
awaitform.
Query arguments
Query functions can accept an argument, such as the slug of an individual post:
<script lang="ts">
import { getPost } from '../data.remote';
let { params } = $props();
const post = $derived(await getPost(params.slug));
</script>
<h1>{post.title}</h1>
<div>{@html post.content}</div><script>
import { getPost } from '../data.remote';
let { params } = $props();
const post = $derived(await getPost(params.slug));
</script>
<h1>{post.title}</h1>
<div>{@html post.content}</div>Since getPost exposes an HTTP endpoint, it’s important to validate this argument to be sure that it’s the correct type. For this, we can use any Standard Schema validation library such as Zod or Valibot:
// @filename: ambient.d.ts
declare module '$lib/server/database' {
export function function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql(strings: TemplateStringsArraystrings: TemplateStringsArraystrings: TemplateStringsArray, ...values: any[]values: any[]values: any[]): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<any[]>;
}
// @filename: index.js
// cut
import * as import vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error } from '@sveltejs/kit';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query } from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database';
export const const getPosts: RemoteQueryFunction<void, void>getPosts = query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(async () => { /* ... */ });
export const const getPost: RemoteQueryFunction<string, any, string>getPost = query<v.StringSchema<undefined>, any>(schema: v.StringSchema<undefined>, fn: (arg: string) => any): RemoteQueryFunction<string, any, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(import vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), async (slug: stringslug) => {
const [const post: anypost] = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql`
SELECT * FROM post
WHERE slug = ${slug: stringslug}
`;
if (!const post: anypost) function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error(404, 'Not found');
return const post: anypost;
});Both the argument and the return value are serialized with devalue, which handles types like Date and Map (and custom types defined in your transport hook) in addition to JSON.
For
queryandprerenderarguments (but not return values), objects, maps, and sets are sorted so that instances with the same members result in the same cache key. For example,getPosts({ limit: 10, offset: 10 })andgetPosts({ offset: 10, limit: 10 })will result in the same cache key. If order is important to you, you’ll have to use an array.
Deduplication
When you call a query function, SvelteKit serializes the argument you call it with and uses it as a cache key. On the server, this is used to create a request-scoped cache so that multiple invocations of the same query only result in the work happening once. On the client, SvelteKit does something similar: Multiple identical invocations of a query all point to the same instance.
You can await a query in any context — components, event handlers, universal load functions, async callbacks — and SvelteKit will dedupe with whatever other consumers are using the same query. For example:
<script lang="ts">
import { getData } from './data.remote.js';
// awaited inside the component template — populates the cache
const data = getData();
</script>
<p>{await data}</p>
<!-- this dedupes with the component-level use above; no extra request -->
<button onclick={async () => console.log(await getData())}>
click me!
</button><script>
import { getData } from './data.remote.js';
// awaited inside the component template — populates the cache
const data = getData();
</script>
<p>{await data}</p>
<!-- this dedupes with the component-level use above; no extra request -->
<button onclick={async () => console.log(await getData())}>
click me!
</button>The cache is shared as long as the query is in active use — rendered in a component, currently being awaited, or otherwise referenced. Once nothing is using it, the cached value is released.
Refreshing queries
Any query can be re-fetched via its refresh method, which retrieves the latest value from the server:
<button onclick={() => getPosts().refresh()}>
Check for new posts
</button>Queries are cached while they’re on the page, meaning
getPosts() === getPosts(). This means you don’t need a reference likeconst posts = getPosts()in order to update the query.
query.batch
query.batch works like query except that it batches requests that happen within the same macrotask. This solves the so-called n+1 problem: rather than each query resulting in a separate database call (for example), simultaneous queries are grouped together.
On the server, the callback receives an array of the arguments the function was called with. It must return a function of the form (input: Input, index: number) => Output. SvelteKit will then call this with each of the input arguments to resolve the individual calls with their results.
// @filename: ambient.d.ts
declare module '$lib/server/database' {
export function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>;
}
// @filename: index.js
// cut
import * as v from 'valibot';
import { query } from '$app/server';
import * as db from '$lib/server/database';
export const getWeather = query.batch(v.string(), async (cityIds) => {
const weather = await db.sql`
SELECT * FROM weather
WHERE city_id = ANY(${cityIds})
`;
const lookup = new Map(weather.map(w => [w.city_id, w]));
return (cityId) => lookup.get(cityId);
});<script lang="ts">
import CityWeather from './CityWeather.svelte';
import { getWeather } from './weather.remote';
let { cities } = $props();
let limit = $state(5);
</script>
<h2>Weather</h2>
{#each cities.slice(0, limit) as city}
<h3>{city.name}</h3>
<CityWeather weather={await getWeather(city.id)} />
{/each}
{#if cities.length > limit}
<button onclick={() => limit += 5}>
Load more
</button>
{/if}<script>
import CityWeather from './CityWeather.svelte';
import { getWeather } from './weather.remote';
let { cities } = $props();
let limit = $state(5);
</script>
<h2>Weather</h2>
{#each cities.slice(0, limit) as city}
<h3>{city.name}</h3>
<CityWeather weather={await getWeather(city.id)} />
{/each}
{#if cities.length > limit}
<button onclick={() => limit += 5}>
Load more
</button>
{/if}query.live
query.live is for accessing real-time data from the server. It behaves similarly to query, but the callback — typically an async generator function — returns an AsyncIterable:
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query } from '$app/server';
export const const getTime: RemoteLiveQueryFunction<void, Date>const getTime: RemoteLiveQueryFunction<void, Date>getTime = function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query.function query.live<Date>(fn: (arg: void) => RemoteLiveQueryUserFunctionReturnType<Date>): RemoteLiveQueryFunction<void, Date> (+2 overloads)Creates a live remote query. When called from the browser, the function will be invoked on the server via a streaming fetch call.
See Remote functions for full documentation.
function query.live<Date>(fn: (arg: void) => RemoteLiveQueryUserFunctionReturnType<Date>): RemoteLiveQueryFunction<void, Date> (+2 overloads)Creates a live remote query. When called from the browser, the function will be invoked on the server via a streaming fetch call.
See Remote functions for full documentation.
live(async function* () {
while (true) {
yield new var Date: DateConstructor
new () => Date (+4 overloads)
var Date: DateConstructor
new () => Date (+4 overloads)
Date();
await new var Promise: PromiseConstructor
new <any>(executor: (resolve: (value: any) => void, reject: (reason?: any) => void) => void) => Promise<any>
Creates a new Promise.
var Promise: PromiseConstructor
new <any>(executor: (resolve: (value: any) => void, reject: (reason?: any) => void) => void) => Promise<any>
Creates a new Promise.
Promise((f: (value: any) => voidf: (value: any) => voidf) => function setTimeout<[value: any]>(callback: (value: any) => void, delay?: number, value?: any): NodeJS.Timeout (+1 overload)function setTimeout<[value: any]>(callback: (value: any) => void, delay?: number, value?: any): NodeJS.Timeout (+1 overload)setTimeout(f: (value: any) => voidf: (value: any) => voidf, 1000));
}
});During server-side rendering, await getTime() returns the first yielded value then closes the iterator. This initial value is serialized and reused during hydration.
On the client, the query stays connected while it’s actively used in a component. Multiple instances share a connection. When there are no active uses left, the stream disconnects and server-side iteration is stopped.
Live queries expose a connected property and reconnect() method:
<script lang="ts">
import { getTime } from './time.remote.js';
const time = getTime();
</script>
<p>{await time}</p>
<p>connected: {time.connected}</p>
<button onclick={() => time.reconnect()}>Reconnect</button><script>
import { getTime } from './time.remote.js';
const time = getTime();
</script>
<p>{await time}</p>
<p>connected: {time.connected}</p>
<button onclick={() => time.reconnect()}>Reconnect</button>If the connection drops, connected becomes false. SvelteKit will attempt to reconnect passively, with exponential backoff, and actively if navigator.onLine goes from false to true.
Unlike query, live queries do not have a refresh() method, as they are self-updating.
If you need direct, imperative access to the underlying stream of values (rather than the reactive current property), live query instances are themselves async-iterable. You can for await over the instance directly:
// @filename: time.remote.ts
import { type RemoteLiveQueryFunction<Input, Output, _Validated = Input> = (arg: undefined extends Input ? Input | void : Input) => RemoteLiveQuery<Output>The type of a remote query.live function. See Remote functions for full documentation.
The optional Validated generic parameter represents the argument type after the
query's schema has validated and (optionally) transformed it, and matches the type
yielded by requested.
RemoteLiveQueryFunction } from '@sveltejs/kit';
export declare const const getTime: RemoteLiveQueryFunction<undefined, Date>getTime: type RemoteLiveQueryFunction<Input, Output, _Validated = Input> = (arg: undefined extends Input ? Input | void : Input) => RemoteLiveQuery<Output>The type of a remote query.live function. See Remote functions for full documentation.
The optional Validated generic parameter represents the argument type after the
query's schema has validated and (optionally) transformed it, and matches the type
yielded by requested.
RemoteLiveQueryFunction<undefined, Date>;
// @filename: index.js
import { getTime } from './time.remote.js';
// cut
async function logTimes() {
for await (const value of getTime()) {
console.log(value);
if (someCondition) break; }
}Multiple consumers of the same live query (whether reactive — via await or current — or imperative for await loops) share a single underlying connection. The first value yielded to a for await iterator is the most-recently-received value, if one is already available, mirroring the semantics of awaiting the resource directly. Subsequent yields fire whenever a new value arrives from the server. If values arrive faster than the consumer drains the iterator, only the latest pending value is kept — live streams are not event logs.
On the server, for await likewise joins a per-request shared iteration of the underlying generator, so concurrent consumers within the same request don’t run the user-defined generator multiple times.
It’s essential that you don’t cache live query responses in a service worker, since the cloned response will continue streaming long after the page is closed. Make sure that your caching logic excludes any responses with a
Cache-Controlheader that includesno-store.
form
The form function makes it easy to write data to the server. It takes a callback that receives data constructed from the submitted FormData…
// @filename: ambient.d.ts
declare module '$lib/server/database' {
export function function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql(strings: TemplateStringsArraystrings: TemplateStringsArraystrings: TemplateStringsArray, ...values: any[]values: any[]values: any[]): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<any[]>;
}
declare module '$lib/server/auth' {
interface User {
User.name: stringUser.name: stringname: string;
}
/**
* Gets a user's info from their cookies, using `getRequestEvent`
*/
export function function getUser(): Promise<User | null>Gets a user's info from their cookies, using getRequestEvent
function getUser(): Promise<User | null>Gets a user's info from their cookies, using getRequestEvent
getUser(): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<User | null>;
}
// @filename: index.js
// cut
import * as import vimport vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error, function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query, function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form } from '$app/server';
import * as module db
const db: any
module db
const db: any
db from '$lib/server/database';
import * as module "$lib/server/auth"module auth
const auth: any
auth from '$lib/server/auth';
export const const getPosts: RemoteQueryFunction<void, void>const getPosts: RemoteQueryFunction<void, void>getPosts = query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(async () => { /* ... */ });
export const const getPost: RemoteQueryFunction<string, void, string>const getPost: RemoteQueryFunction<string, void, string>getPost = query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), async (slug: stringslug: stringslug) => { /* ... */ });
export const const createPost: RemoteForm<{
title: string;
content: string;
}, never>
const createPost: RemoteForm<{
title: string;
content: string;
}, never>
createPost = form<v.ObjectSchema<{
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}, undefined>, never>(validate: v.ObjectSchema<{
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}, undefined>, fn: (data: {
...;
}, issue: {
...;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<...>): RemoteForm<...> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}, undefined>, never>(validate: v.ObjectSchema<{
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}, undefined>, fn: (data: {
...;
}, issue: {
...;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<...>): RemoteForm<...> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vimport vv.object<{
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}>(entries: {
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}): v.ObjectSchema<{
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}>(entries: {
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}): v.ObjectSchema<{
readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
readonly content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({
title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>title: import vimport vv.pipe<v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>>(schema: v.StringSchema<undefined>, item1: v.NonEmptyAction<string, undefined> | v.PipeAction<string, string, v.NonEmptyIssue<string>>): v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]> (+20 overloads)
export pipe
Adds a pipeline to a schema, that can validate and transform its input.
pipe<v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>>(schema: v.StringSchema<undefined>, item1: v.NonEmptyAction<string, undefined> | v.PipeAction<string, string, v.NonEmptyIssue<string>>): v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]> (+20 overloads)
export pipe
Adds a pipeline to a schema, that can validate and transform its input.
pipe(import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), import vimport vv.nonEmpty<string>(): v.NonEmptyAction<string, undefined> (+1 overload)
export nonEmpty
Creates a non-empty validation action.
nonEmpty<string>(): v.NonEmptyAction<string, undefined> (+1 overload)
export nonEmpty
Creates a non-empty validation action.
nonEmpty()),
content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>content: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>content:import vimport vv.pipe<v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>>(schema: v.StringSchema<undefined>, item1: v.NonEmptyAction<string, undefined> | v.PipeAction<string, string, v.NonEmptyIssue<string>>): v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]> (+20 overloads)
export pipe
Adds a pipeline to a schema, that can validate and transform its input.
pipe<v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>>(schema: v.StringSchema<undefined>, item1: v.NonEmptyAction<string, undefined> | v.PipeAction<string, string, v.NonEmptyIssue<string>>): v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]> (+20 overloads)
export pipe
Adds a pipeline to a schema, that can validate and transform its input.
pipe(import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), import vimport vv.nonEmpty<string>(): v.NonEmptyAction<string, undefined> (+1 overload)
export nonEmpty
Creates a non-empty validation action.
nonEmpty<string>(): v.NonEmptyAction<string, undefined> (+1 overload)
export nonEmpty
Creates a non-empty validation action.
nonEmpty())
}),
async ({ title: stringtitle: stringtitle, content: stringcontent: stringcontent }) => {
// Check the user is logged in
const const user: auth.User | nullconst user: anyuser = await module "$lib/server/auth"module auth
const auth: any
auth.function getUser(): Promise<auth.User | null>Gets a user's info from their cookies, using getRequestEvent
getUser();
if (!const user: auth.User | nullconst user: anyuser) function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error(401, 'Unauthorized');
const const slug: stringconst slug: stringslug = title: stringtitle: stringtitle.String.toLowerCase(): stringConverts all the alphabetic characters in a string to lowercase.
String.toLowerCase(): stringConverts all the alphabetic characters in a string to lowercase.
toLowerCase().String.replace(searchValue: {
[Symbol.replace](string: string, replaceValue: string): string;
}, replaceValue: string): string (+3 overloads)
Passes a string and
{@linkcode
replaceValue
}
to the [Symbol.replace] method on
{@linkcode
searchValue
}
. This method is expected to implement its own replacement algorithm.
String.replace(searchValue: {
[Symbol.replace](string: string, replaceValue: string): string;
}, replaceValue: string): string (+3 overloads)
Passes a string and
{@linkcode
replaceValue
}
to the [Symbol.replace] method on
{@linkcode
searchValue
}
. This method is expected to implement its own replacement algorithm.
replace(/ /g, '-');
// Insert into the database
await module db
const db: any
module db
const db: any
db.sql`
INSERT INTO post (slug, title, content)
VALUES (${const slug: stringconst slug: stringslug}, ${title: stringtitle: stringtitle}, ${content: stringcontent: stringcontent})
`;
// Redirect to the newly created page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
redirect(303, `/blog/${const slug: stringconst slug: stringslug}`);
}
);…and returns an object that can be spread onto a <form> element. The callback is called whenever the form is submitted.
<script lang="ts">
import { createPost } from '../data.remote';
</script>
<h1>Create a new post</h1>
<form {...createPost}>
<!-- form content goes here -->
<button>Publish!</button>
</form><script>
import { createPost } from '../data.remote';
</script>
<h1>Create a new post</h1>
<form {...createPost}>
<!-- form content goes here -->
<button>Publish!</button>
</form>The form object contains method and action properties that allow it to work without JavaScript (i.e. it submits data and reloads the page). It also has an attachment that progressively enhances the form when JavaScript is available, submitting data without reloading the entire page.
As with query, if the callback uses the submitted data, it should be validated by passing a Standard Schema as the first argument to form.
Fields
A form is composed of a set of fields, which are defined by the schema. In the case of createPost, we have two fields, title and content, which are both strings. To get the attributes for a field, call its .as(...) method, specifying which input type to use. For most input types, you can also pass a second argument — .as(type, value) — to control the rendered value:
<form {...createPost}>
<label>
<h2>Title</h2>
<input {...createPost.fields.title.as('text')} />
</label>
<label>
<h2>Write your post</h2>
<textarea {...createPost.fields.content.as('text')}></textarea>
</label>
<button>Publish!</button>
</form>These attributes allow SvelteKit to set the correct input type, set a name that is used to construct the data passed to the handler, populate the value of the form (for example following a failed submission, to save the user having to re-enter everything), and set the aria-invalid state.
Passing a second argument to .as(...) is useful when rendering a form from existing data, such as an edit form or multiple instances created with for(...). As well as setting the value of the element when it is rendered, it controls the value of the element when the form is reset. radio, submit and hidden inputs always need this value, and checkbox inputs need it when they represent one option in an array field. file inputs cannot be populated this way.
The generated
nameattribute uses JS object notation (e.g.nested.array[0].value). String keys that require quotes such asobject['nested-array'][0].valueare not supported. Under the hood, boolean checkbox and number field names are prefixed withb:andn:, respectively, to signal SvelteKit to coerce the values from strings prior to validation.
Fields can be nested in objects and arrays, and their values can be strings, numbers, booleans or File objects. For example, if your schema looked like this…
import * as import vimport vv from 'valibot';
import { function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form } from '$app/server';
// cut
const const datingProfile: v.ObjectSchema<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}, undefined>
const datingProfile: v.ObjectSchema<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}, undefined>
datingProfile = import vimport vv.object<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}>(entries: {
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}): v.ObjectSchema<...> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}>(entries: {
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}): v.ObjectSchema<...> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({
name: v.StringSchema<undefined>name: v.StringSchema<undefined>name: import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(),
photo: v.FileSchema<undefined>photo: v.FileSchema<undefined>photo: import vimport vv.function file(): v.FileSchema<undefined> (+1 overload)
export file
Creates a file schema.
function file(): v.FileSchema<undefined> (+1 overload)
export file
Creates a file schema.
file(),
info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>
info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>
info: import vimport vv.object<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}>(entries: {
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}): v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}>(entries: {
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}): v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({
height: v.NumberSchema<undefined>height: v.NumberSchema<undefined>height: import vimport vv.function number(): v.NumberSchema<undefined> (+1 overload)
export number
Creates a number schema.
function number(): v.NumberSchema<undefined> (+1 overload)
export number
Creates a number schema.
number(),
likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>likesDogs: import vimport vv.optional<v.BooleanSchema<undefined>, false>(wrapped: v.BooleanSchema<undefined>, default_: false): v.OptionalSchema<v.BooleanSchema<undefined>, false> (+1 overload)
export optional
Creates an optional schema.
optional<v.BooleanSchema<undefined>, false>(wrapped: v.BooleanSchema<undefined>, default_: false): v.OptionalSchema<v.BooleanSchema<undefined>, false> (+1 overload)
export optional
Creates an optional schema.
optional(import vimport vv.function boolean(): v.BooleanSchema<undefined> (+1 overload)
export boolean
Creates a boolean schema.
function boolean(): v.BooleanSchema<undefined> (+1 overload)
export boolean
Creates a boolean schema.
boolean(), false)
}),
attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>attributes: import vimport vv.array<v.StringSchema<undefined>>(item: v.StringSchema<undefined>): v.ArraySchema<v.StringSchema<undefined>, undefined> (+1 overload)
export array
Creates an array schema.
array<v.StringSchema<undefined>>(item: v.StringSchema<undefined>): v.ArraySchema<v.StringSchema<undefined>, undefined> (+1 overload)
export array
Creates an array schema.
array(import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string())
});
export const const createProfile: RemoteForm<{
name: string;
photo: File;
info: {
height: number;
likesDogs?: boolean | undefined;
};
attributes: string[];
}, void>
const createProfile: RemoteForm<{
name: string;
photo: File;
info: {
height: number;
likesDogs?: boolean | undefined;
};
attributes: string[];
}, void>
createProfile = form<v.ObjectSchema<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}, undefined>, void>(validate: v.ObjectSchema<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}, undefined>, fn: (data: {
...;
}, issue: {
...;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<...>): RemoteForm<...> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}, undefined>, void>(validate: v.ObjectSchema<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}, undefined>, fn: (data: {
...;
}, issue: {
...;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<...>): RemoteForm<...> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(const datingProfile: v.ObjectSchema<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}, undefined>
const datingProfile: v.ObjectSchema<{
readonly name: v.StringSchema<undefined>;
readonly photo: v.FileSchema<undefined>;
readonly info: v.ObjectSchema<{
readonly height: v.NumberSchema<undefined>;
readonly likesDogs: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
}, undefined>;
readonly attributes: v.ArraySchema<v.StringSchema<undefined>, undefined>;
}, undefined>
datingProfile, (data: {
name: string;
photo: File;
info: {
height: number;
likesDogs: boolean;
};
attributes: string[];
}
data: {
name: string;
photo: File;
info: {
height: number;
likesDogs: boolean;
};
attributes: string[];
}
data) => { /* ... */ });…your form could look like this:
<script lang="ts">
import { createProfile } from './data.remote';
const { name, photo, info, attributes } = createProfile.fields;
</script>
<form {...createProfile} enctype="multipart/form-data">
<label>
<input {...name.as('text')} /> Name
</label>
<label>
<input {...photo.as('file')} /> Photo
</label>
<label>
<input {...info.height.as('number')} /> Height (cm)
</label>
<label>
<input {...info.likesDogs.as('checkbox')} /> I like dogs
</label>
<h2>My best attributes</h2>
<input {...attributes[0].as('text')} />
<input {...attributes[1].as('text')} />
<input {...attributes[2].as('text')} />
<button>submit</button>
</form><script>
import { createProfile } from './data.remote';
const { name, photo, info, attributes } = createProfile.fields;
</script>
<form {...createProfile} enctype="multipart/form-data">
<label>
<input {...name.as('text')} /> Name
</label>
<label>
<input {...photo.as('file')} /> Photo
</label>
<label>
<input {...info.height.as('number')} /> Height (cm)
</label>
<label>
<input {...info.likesDogs.as('checkbox')} /> I like dogs
</label>
<h2>My best attributes</h2>
<input {...attributes[0].as('text')} />
<input {...attributes[1].as('text')} />
<input {...attributes[2].as('text')} />
<button>submit</button>
</form>Because our form contains a file input, we’ve added an enctype="multipart/form-data" attribute. The values for info.height and info.likesDogs are coerced to a number and a boolean respectively.
If a
checkboxinput is unchecked, the value is not included in theFormDataobject that SvelteKit constructs the data from. As such, we have to make the value optional in our schema. In Valibot that means usingv.optional(v.boolean(), false)instead of justv.boolean(), whereas in Zod it would mean usingz.coerce.boolean<boolean>().
In the case of radio and checkbox inputs that all belong to the same field, the value must be specified as a second argument to .as(...):
export const const operatingSystems: readonly ["windows", "mac", "linux"]const operatingSystems: readonly ["windows", "mac", "linux"]operatingSystems = ['windows', 'mac', 'linux'] as type const = readonly ["windows", "mac", "linux"]type const = readonly ["windows", "mac", "linux"]const;
export const const languages: readonly ["html", "css", "js"]const languages: readonly ["html", "css", "js"]languages = ['html', 'css', 'js'] as type const = readonly ["html", "css", "js"]type const = readonly ["html", "css", "js"]const;export const const operatingSystems: readonly ["windows", "mac", "linux"]const operatingSystems: readonly ["windows", "mac", "linux"]operatingSystems = /** @type {const} */ (['windows', 'mac', 'linux']);
export const const languages: readonly ["html", "css", "js"]const languages: readonly ["html", "css", "js"]languages = /** @type {const} */ (['html', 'css', 'js']);// @filename: constants.js
export const operatingSystems = ['windows', 'mac', 'linux'] as const;
export const languages = ['html', 'css', 'js'] as const;
// @filename: index.ts
import * as v from 'valibot';
import { form } from '$app/server';
// cut
import { operatingSystems, languages } from './constants';
export const survey = form(
v.object({
operatingSystem: v.picklist(operatingSystems),
languages: v.optional(v.array(v.picklist(languages)), []),
}),
(data) => { /* ... */ },
);// @filename: constants.js
export const const operatingSystems: readonly ["windows", "mac", "linux"]const operatingSystems: readonly ["windows", "mac", "linux"]operatingSystems = /** @type {const} */ (['windows', 'mac', 'linux']);
export const const languages: readonly ["html", "css", "js"]const languages: readonly ["html", "css", "js"]languages = /** @type {const} */ (['html', 'css', 'js']);
// @filename: index.js
import * as import vv from 'valibot';
import { function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form } from '$app/server';
// cut
import { const operatingSystems: readonly ["windows", "mac", "linux"]operatingSystems, const languages: readonly ["html", "css", "js"]languages } from './constants';
export const const survey: RemoteForm<{
operatingSystem: "windows" | "mac" | "linux";
languages?: ("html" | "css" | "js")[] | undefined;
}, void>
survey = form<v.ObjectSchema<{
readonly operatingSystem: v.PicklistSchema<readonly ["windows", "mac", "linux"], undefined>;
readonly languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined>, readonly []>;
}, undefined>, void>(validate: v.ObjectSchema<{
readonly operatingSystem: v.PicklistSchema<readonly ["windows", "mac", "linux"], undefined>;
readonly languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined>, readonly []>;
}, undefined>, fn: (data: {
...;
}, issue: {
...;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<...>): RemoteForm<...> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vv.object<{
readonly operatingSystem: v.PicklistSchema<readonly ["windows", "mac", "linux"], undefined>;
readonly languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined>, readonly []>;
}>(entries: {
readonly operatingSystem: v.PicklistSchema<readonly ["windows", "mac", "linux"], undefined>;
readonly languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined>, readonly []>;
}): v.ObjectSchema<{
readonly operatingSystem: v.PicklistSchema<readonly ["windows", "mac", "linux"], undefined>;
readonly languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined>, readonly []>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({
operatingSystem: v.PicklistSchema<readonly ["windows", "mac", "linux"], undefined>operatingSystem: import vv.picklist<readonly ["windows", "mac", "linux"]>(options: readonly ["windows", "mac", "linux"]): v.PicklistSchema<readonly ["windows", "mac", "linux"], undefined> (+1 overload)
export picklist
Creates a picklist schema.
picklist(const operatingSystems: readonly ["windows", "mac", "linux"]operatingSystems),
languages: v.OptionalSchema<v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined>, readonly []>languages: import vv.optional<v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined>, readonly []>(wrapped: v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined>, default_: readonly []): v.OptionalSchema<v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined>, readonly []> (+1 overload)
export optional
Creates an optional schema.
optional(import vv.array<v.PicklistSchema<readonly ["html", "css", "js"], undefined>>(item: v.PicklistSchema<readonly ["html", "css", "js"], undefined>): v.ArraySchema<v.PicklistSchema<readonly ["html", "css", "js"], undefined>, undefined> (+1 overload)
export array
Creates an array schema.
array(import vv.picklist<readonly ["html", "css", "js"]>(options: readonly ["html", "css", "js"]): v.PicklistSchema<readonly ["html", "css", "js"], undefined> (+1 overload)
export picklist
Creates a picklist schema.
picklist(const languages: readonly ["html", "css", "js"]languages)), []),
}),
(data: {
operatingSystem: "windows" | "mac" | "linux";
languages: ("html" | "css" | "js")[];
}
data) => { /* ... */ },
);<form {...survey}>
<h2>Which operating system do you use?</h2>
{#each operatingSystems as os}
<label>
<input {...survey.fields.operatingSystem.as('radio', os)}>
{os}
</label>
{/each}
<h2>Which languages do you write code in?</h2>
{#each languages as language}
<label>
<input {...survey.fields.languages.as('checkbox', language)}>
{language}
</label>
{/each}
<button>submit</button>
</form>Alternatively, you could use select and select multiple:
<form {...survey}>
<h2>Which operating system do you use?</h2>
<select {...survey.fields.operatingSystem.as('select')}>
{#each operatingSystems as os}
<option>{os}</option>
{/each}
</select>
<h2>Which languages do you write code in?</h2>
<select {...survey.fields.languages.as('select multiple')}>
{#each languages as language}
<option>{language}</option>
{/each}
</select>
<button>submit</button>
</form>As with unchecked
checkboxinputs, if no selections are made then the data will beundefined. For this reason, thelanguagesfield usesv.optional(v.array(...), [])rather than justv.array(...).
Programmatic validation
In addition to declarative schema validation, you can programmatically mark fields as invalid inside the form handler using the invalid helper from @sveltejs/kit. This is useful for cases where you can’t know if something is valid until you try to perform some action.
- It throws just like
redirectorerror - It accepts multiple arguments that can be strings (for issues relating to the form as a whole — these will only show up in
fields.allIssues()) or standard-schema-compliant issues (for those relating to a specific field). Use theissueparameter for type-safe creation of such issues:
// @filename: ambient.d.ts
declare module '$lib/server/database' {
export function function buy(qty: number): Promise<void>buy(qty: numberqty: number): interface Promise<T>Represents the completion of an asynchronous operation
Promise<void>
}
// @filename: index.js
// cut
import * as v from 'valibot';
import { invalid } from '@sveltejs/kit';
import { form } from '$app/server';
import * as db from '$lib/server/database';
export const buyHotcakes = form(
v.object({
qty: v.pipe(
v.number(),
v.minValue(1, 'you must buy at least one hotcake')
)
}),
async (data, issue) => {
try {
await db.buy(data.qty);
} catch (e) {
if (e.code === 'OUT_OF_STOCK') { invalid(
issue.qty(`we don't have enough hotcakes`)
);
}
}
}
);Validation
If the submitted data doesn’t pass the schema, the callback will not run. Instead, each invalid field’s issues() method will return an array of { message: string } objects, and the aria-invalid attribute (returned from as(...)) will be set to true:
<form {...createPost}>
<label>
<h2>Title</h2>
{#each createPost.fields.title.issues() as issue}
<p class="issue">{issue.message}</p>
{/each}
<input {...createPost.fields.title.as('text')} />
</label>
<label>
<h2>Write your post</h2>
{#each createPost.fields.content.issues() as issue}
<p class="issue">{issue.message}</p>
{/each}
<textarea {...createPost.fields.content.as('text')}></textarea>
</label>
<button>Publish!</button>
</form>If the title is valid, or has not yet been validated, createPost.fields.title.issues() will return undefined.
You don’t need to wait until the form is submitted to validate the data — you can call validate() programmatically, for example in an oninput callback (which will validate the data on every keystroke) or an onchange callback:
<form {...createPost} oninput={() => createPost.validate()}>
<!-- -->
</form>By default, issues will be ignored if they belong to form controls that haven’t yet been interacted with. To validate all inputs, call validate({ includeUntouched: true }).
For client-side validation, you can specify a preflight schema which will populate issues() and prevent data being sent to the server if the data doesn’t validate:
<script lang="ts">
import * as v from 'valibot';
import { createPost } from '../data.remote';
const schema = v.object({
title: v.pipe(v.string(), v.nonEmpty()),
content: v.pipe(v.string(), v.nonEmpty())
});
</script>
<h1>Create a new post</h1>
<form {...createPost.preflight(schema)}>
<!-- -->
</form><script>
import * as v from 'valibot';
import { createPost } from '../data.remote';
const schema = v.object({
title: v.pipe(v.string(), v.nonEmpty()),
content: v.pipe(v.string(), v.nonEmpty())
});
</script>
<h1>Create a new post</h1>
<form {...createPost.preflight(schema)}>
<!-- -->
</form>The preflight schema can be the same object as your server-side schema, if appropriate, though it won’t be able to do server-side checks like ‘this value already exists in the database’. Note that you cannot export a schema from a
.remote.tsor.remote.jsfile, so the schema must either be exported from a shared module, or from a<script module>block in the component containing the<form>.
To get a list of all issues, rather than just those belonging to a single field, you can use the fields.allIssues() method:
{#each createPost.fields.allIssues() as issue}
<p>{issue.message}</p>
{/each}As with individual fields, createPost.fields.allIssues() will return undefined if the form as a whole is valid (or has not yet been validated).
Getting/setting inputs
Each field has a value() method that reflects its current value. As the user interacts with the form, it is automatically updated:
<form {...createPost}>
<!-- -->
</form>
<div class="preview">
<h2>{createPost.fields.title.value()}</h2>
<div>{@html render(createPost.fields.content.value())}</div>
</div>Alternatively, createPost.fields.value() would return a { title, content } object.
The value() of a field does not reflect defaults provided as a second argument to as (as in fields.title.as('text', '...')) until it is edited or submitted. You can programmatically update a field (or a collection of fields) via the set(...) method:
<script lang="ts">
import { createPost } from '../data.remote';
// this...
createPost.fields.set({
title: 'My new blog post',
content: 'Lorem ipsum dolor sit amet...'
});
// ...is equivalent to this:
createPost.fields.title.set('My new blog post');
createPost.fields.content.set('Lorem ipsum dolor sit amet');
</script><script>
import { createPost } from '../data.remote';
// this...
createPost.fields.set({
title: 'My new blog post',
content: 'Lorem ipsum dolor sit amet...'
});
// ...is equivalent to this:
createPost.fields.title.set('My new blog post');
createPost.fields.content.set('Lorem ipsum dolor sit amet');
</script>Handling sensitive data
In the case of a non-progressively-enhanced form submission (i.e. where JavaScript is unavailable, for whatever reason) value() is also populated if the submitted data is invalid, so that the user does not need to fill the entire form out from scratch.
You can prevent sensitive data (such as passwords and credit card numbers) from being sent back to the user by using a name with a leading underscore:
<form {...register}>
<label>
Username
<input {...register.fields.username.as('text')} />
</label>
<label>
Password
<input {...register.fields._password.as('password')} />
</label>
<button>Sign up!</button>
</form>In this example, if the data does not validate, only the first <input> will be populated when the page reloads.
Returns and redirects
The example above uses redirect(...), which sends the user to the newly created page. Alternatively, the callback could return data, in which case it would be available as createPost.result:
// @filename: ambient.d.ts
declare module '$lib/server/database' {
export function function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql(strings: TemplateStringsArraystrings: TemplateStringsArraystrings: TemplateStringsArray, ...values: any[]values: any[]values: any[]): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<any[]>;
}
declare module '$lib/server/auth' {
interface User {
User.name: stringUser.name: stringname: string;
}
/**
* Gets a user's info from their cookies, using `getRequestEvent`
*/
export function function getUser(): Promise<User | null>Gets a user's info from their cookies, using getRequestEvent
function getUser(): Promise<User | null>Gets a user's info from their cookies, using getRequestEvent
getUser(): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<User | null>;
}
// @filename: index.js
import * as import vimport vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error, function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query, function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form } from '$app/server';
import * as module "$lib/server/database"module db
const db: any
db from '$lib/server/database';
import * as module "$lib/server/auth"module auth
const auth: any
auth from '$lib/server/auth';
export const const getPosts: RemoteQueryFunction<void, void>const getPosts: RemoteQueryFunction<void, void>getPosts = query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(async () => { /* ... */ });
export const const getPost: RemoteQueryFunction<string, void, string>const getPost: RemoteQueryFunction<string, void, string>getPost = query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), async (slug: stringslug: stringslug) => { /* ... */ });
// cut
export const const createPost: RemoteForm<{}, {
success: boolean;
}>
const createPost: RemoteForm<{}, {
success: boolean;
}>
createPost = form<v.ObjectSchema<{}, undefined>, {
success: boolean;
}>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<{
success: boolean;
}>): RemoteForm<{}, {
success: boolean;
}> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{}, undefined>, {
success: boolean;
}>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<{
success: boolean;
}>): RemoteForm<{}, {
success: boolean;
}> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vimport vv.object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({/* ... */}),
async (data: {}data: {}data) => {
// ...
return { success: booleansuccess: booleansuccess: true };
}
);<script lang="ts">
import { createPost } from '../data.remote';
</script>
<h1>Create a new post</h1>
<form {...createPost}>
<!-- -->
</form>
{#if createPost.result?.success}
<p>Successfully published!</p>
{/if}<script>
import { createPost } from '../data.remote';
</script>
<h1>Create a new post</h1>
<form {...createPost}>
<!-- -->
</form>
{#if createPost.result?.success}
<p>Successfully published!</p>
{/if}This value is ephemeral — it will vanish if you resubmit, navigate away, or reload the page.
The
resultvalue need not indicate success — it can also contain validation errors, along with any data that should repopulate the form on page reload.
If an error occurs during submission, the nearest +error.svelte page will be rendered.
enhance
We can customize what happens when the form is submitted with the enhance method:
<script lang="ts">
import { createPost } from '../data.remote';
import { showToast } from '$lib/toast';
</script>
<h1>Create a new post</h1>
<form {...createPost.enhance(async (form) => {
try {
if (await form.submit()) {
form.element.reset();
showToast('Successfully published!');
} else {
showToast('Invalid data!');
}
} catch (error) {
showToast('Oh no! Something went wrong');
}
})}>
<!-- -->
</form><script>
import { createPost } from '../data.remote';
import { showToast } from '$lib/toast';
</script>
<h1>Create a new post</h1>
<form {...createPost.enhance(async (form) => {
try {
if (await form.submit()) {
form.element.reset();
showToast('Successfully published!');
} else {
showToast('Invalid data!');
}
} catch (error) {
showToast('Oh no! Something went wrong');
}
})}>
<!-- -->
</form>When using
enhance, the<form>is not automatically reset — you must callform.element.reset()if you want to clear the inputs.
The callback receives a copy of the form instance. It has all the same properties and methods except enhance, and form.submit() performs the submission directly without re-running the enhance callback. Inside the callback, form.element is always defined.
Multiple instances of a form
Some forms may be repeated as part of a list. In this case you can create separate instances of a form function via for(id) to achieve isolation.
When each instance should render different values, pass them as the second argument to .as(...):
<script lang="ts">
import { getTodos, modifyTodo } from '../data.remote';
</script>
<h1>Todos</h1>
{#each await getTodos() as todo}
{@const modify = modifyTodo.for(todo.id)}
<form {...modify}>
<input {...modify.fields.description.as('text', todo.description)} />
<button disabled={!!modify.pending}>save changes</button>
</form>
{/each}<script>
import { getTodos, modifyTodo } from '../data.remote';
</script>
<h1>Todos</h1>
{#each await getTodos() as todo}
{@const modify = modifyTodo.for(todo.id)}
<form {...modify}>
<input {...modify.fields.description.as('text', todo.description)} />
<button disabled={!!modify.pending}>save changes</button>
</form>
{/each}Multiple submit buttons
It’s possible for a <form> to have multiple submit buttons. For example, you might have a single form that allows you to log in or register depending on which button was clicked.
To accomplish this, add a field to your schema for the button value, and use as('submit', value) to bind it:
In your form handler, you can check which button was clicked:
import * as import vimport vv from 'valibot';
import { function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form } from '$app/server';
export const const loginOrRegister: RemoteForm<{
username: string;
_password: string;
action: "login" | "register";
}, void>
const loginOrRegister: RemoteForm<{
username: string;
_password: string;
action: "login" | "register";
}, void>
loginOrRegister = form<v.ObjectSchema<{
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}, undefined>, void>(validate: v.ObjectSchema<{
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}, undefined>, fn: (data: {
username: string;
_password: string;
action: "login" | "register";
}, issue: {
username: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
_password: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
action: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<...>): RemoteForm<...> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}, undefined>, void>(validate: v.ObjectSchema<{
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}, undefined>, fn: (data: {
username: string;
_password: string;
action: "login" | "register";
}, issue: {
username: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
_password: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
action: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<...>): RemoteForm<...> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vimport vv.object<{
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}>(entries: {
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}): v.ObjectSchema<{
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}>(entries: {
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}): v.ObjectSchema<{
readonly username: v.StringSchema<undefined>;
readonly _password: v.StringSchema<undefined>;
readonly action: v.PicklistSchema<["login", "register"], undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({
username: v.StringSchema<undefined>username: v.StringSchema<undefined>username: import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(),
_password: v.StringSchema<undefined>_password: v.StringSchema<undefined>_password: import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(),
action: v.PicklistSchema<["login", "register"], undefined>action: v.PicklistSchema<["login", "register"], undefined>action: import vimport vv.picklist<["login", "register"]>(options: ["login", "register"]): v.PicklistSchema<["login", "register"], undefined> (+1 overload)
export picklist
Creates a picklist schema.
picklist<["login", "register"]>(options: ["login", "register"]): v.PicklistSchema<["login", "register"], undefined> (+1 overload)
export picklist
Creates a picklist schema.
picklist(['login', 'register'])
}),
async ({ username: stringusername: stringusername, _password: string_password: string_password, action: "login" | "register"action: "login" | "register"action }) => {
if (action: "login" | "register"action: "login" | "register"action === 'login') {
// handle login
} else {
// handle registration
}
}
);command
The command function, like form, allows you to write data to the server. Unlike form, it’s not specific to an element and can be called from anywhere.
Prefer
formwhere possible, since it gracefully degrades if JavaScript is disabled or fails to load.
As with query and form, if the function accepts an argument, it should be validated by passing a Standard Schema as the first argument to command.
// @filename: ambient.d.ts
declare module '$lib/server/database' {
export function function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql(strings: TemplateStringsArraystrings: TemplateStringsArraystrings: TemplateStringsArray, ...values: any[]values: any[]values: any[]): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<any[]>;
}
// @filename: index.js
// cut
import * as import vimport vv from 'valibot';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query, function command<Output>(fn: () => MaybePromise<Output>): RemoteCommand<void, Output> (+2 overloads)Creates a remote command. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function command<Output>(fn: () => MaybePromise<Output>): RemoteCommand<void, Output> (+2 overloads)Creates a remote command. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
command } from '$app/server';
import * as module "$lib/server/database"module db
const db: any
db from '$lib/server/database';
export const const getLikes: RemoteQueryFunction<string, any, string>const getLikes: RemoteQueryFunction<string, any, string>getLikes = query<v.StringSchema<undefined>, any>(schema: v.StringSchema<undefined>, fn: (arg: string) => any): RemoteQueryFunction<string, any, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<v.StringSchema<undefined>, any>(schema: v.StringSchema<undefined>, fn: (arg: string) => any): RemoteQueryFunction<string, any, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), async (id: stringid: stringid) => {
const [const row: anyconst row: anyrow] = await module "$lib/server/database"module db
const db: any
db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql`
SELECT likes
FROM item
WHERE id = ${id: stringid: stringid}
`;
return const row: anyconst row: anyrow.likes;
});
export const const addLike: RemoteCommand<string, void>const addLike: RemoteCommand<string, void>addLike = command<v.StringSchema<undefined>, void>(validate: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteCommand<string, void> (+2 overloads)Creates a remote command. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
command<v.StringSchema<undefined>, void>(validate: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteCommand<string, void> (+2 overloads)Creates a remote command. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
command(import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), async (id: stringid: stringid) => {
await module "$lib/server/database"module db
const db: any
db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql`
UPDATE item
SET likes = likes + 1
WHERE id = ${id: stringid: stringid}
`;
});Now simply call addLike, from (for example) an event handler:
<script lang="ts">
import { getLikes, addLike } from './likes.remote';
import { showToast } from '$lib/toast';
let { item } = $props();
</script>
<button
onclick={async () => {
try {
await addLike(item.id);
} catch (error) {
showToast('Something went wrong!');
}
}}
>
add like
</button>
<p>likes: {await getLikes(item.id)}</p><script>
import { getLikes, addLike } from './likes.remote';
import { showToast } from '$lib/toast';
let { item } = $props();
</script>
<button
onclick={async () => {
try {
await addLike(item.id);
} catch (error) {
showToast('Something went wrong!');
}
}}
>
add like
</button>
<p>likes: {await getLikes(item.id)}</p>Commands cannot be called during render.
Single-flight mutations
The purpose of both form and command is mutating data. In many cases, mutating data invalidates other data. By default, form deals with this by automatically invalidating all queries and load functions following a successful submission, to emulate what would happen with a traditional full-page reload. command, on the other hand, does nothing. Typically, neither of these options is going to be the ideal solution — invalidating everything is likely wasteful, as it’s unlikely a form submission changed everything being displayed on your webpage. In the case of command, doing nothing likely under-invalidates your app, leaving stale data displayed. In both cases, it’s common to have to perform two round-trips to the server: One to run the mutation, and another after that completes to re-request the data from any queries you need to refresh.
SvelteKit solves both of these problems with single-flight mutations: Your form submission or command invocation can refresh queries and pass their results back to the client in a single request.
Server-driven refreshes
In most circumstances, the server handler knows what client data needs to be updated based on its arguments:
import * as import vimport vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error, function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query, function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form } from '$app/server';
const const slug: ""const slug: ""slug = '';
const const post: {
id: string;
}
const post: {
id: string;
}
post = { id: stringid: stringid: '' };
const const externalApi: anyconst externalApi: anyexternalApi: any = '';
// cut
export const const getPosts: RemoteQueryFunction<void, void>const getPosts: RemoteQueryFunction<void, void>getPosts = query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(async () => { /* ... */ });
export const const getPost: RemoteQueryFunction<string, void, string>const getPost: RemoteQueryFunction<string, void, string>getPost = query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), async (slug: stringslug: stringslug) => { /* ... */ });
export const const createPost: RemoteForm<{}, never>const createPost: RemoteForm<{}, never>createPost = form<v.ObjectSchema<{}, undefined>, never>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<never>): RemoteForm<{}, never> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{}, undefined>, never>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<never>): RemoteForm<{}, never> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vimport vv.object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({/* ... */}),
async (data: {}data: {}data) => {
// form logic goes here...
// Refresh `getPosts()` on the server, and send
// the data back with the result of `createPost`
// it's safe to throw away the promise from `refresh`,
// as the framework awaits it for us before serving the response
void const getPosts: (arg: void) => RemoteQuery<void>const getPosts: (arg: void) => RemoteQuery<void>getPosts().function refresh(): Promise<void>On the client, this function will re-fetch the query from the server.
On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
function refresh(): Promise<void>On the client, this function will re-fetch the query from the server.
On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
refresh();
// Redirect to the newly created page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
redirect(303, `/blog/${const slug: ""const slug: ""slug}`);
}
);
export const const updatePost: RemoteForm<{
id: string;
}, void>
const updatePost: RemoteForm<{
id: string;
}, void>
updatePost = form<v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined>, void>(validate: v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined>, fn: (data: {
id: string;
}, issue: {
id: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<void>): RemoteForm<{
id: string;
}, void> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined>, void>(validate: v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined>, fn: (data: {
id: string;
}, issue: {
id: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<void>): RemoteForm<{
id: string;
}, void> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vimport vv.object<{
readonly id: v.StringSchema<undefined>;
}>(entries: {
readonly id: v.StringSchema<undefined>;
}): v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{
readonly id: v.StringSchema<undefined>;
}>(entries: {
readonly id: v.StringSchema<undefined>;
}): v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({ id: v.StringSchema<undefined>id: v.StringSchema<undefined>id: import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string() }),
async (post: {
id: string;
}
post: {
id: string;
}
post) => {
// form logic goes here...
const const result: anyconst result: anyresult = const externalApi: anyconst externalApi: anyexternalApi.update(post: {
id: string;
}
post: {
id: string;
}
post);
// The API already gives us the updated post,
// no need to refresh it, we can set it directly
const getPost: (arg: string) => RemoteQuery<void>const getPost: (arg: string) => RemoteQuery<void>getPost(post: {
id: string;
}post: {
id: string;
}post.id: stringid: stringid).function set(value: void): voidOn the client, this function will update the value of the query without re-fetching it.
On the server, this can be called in the context of a command or form and the specified data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
function set(value: void): voidOn the client, this function will update the value of the query without re-fetching it.
On the server, this can be called in the context of a command or form and the specified data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
const result: anyconst result: anyresult);
}
);import * as import vimport vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error, function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query, function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form } from '$app/server';
const const slug: ""const slug: ""slug = '';
const const post: {
id: string;
}
const post: {
id: string;
}
post = { id: stringid: stringid: '' };
/** @type {any} */
const const externalApi: anyconst externalApi: anyexternalApi = '';
// cut
export const const getPosts: RemoteQueryFunction<void, void>const getPosts: RemoteQueryFunction<void, void>getPosts = query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<void>(fn: () => MaybePromise<void>): RemoteQueryFunction<void, void> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(async () => { /* ... */ });
export const const getPost: RemoteQueryFunction<string, void, string>const getPost: RemoteQueryFunction<string, void, string>getPost = query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>): RemoteQueryFunction<string, void, string> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), async (slug: stringslug: stringslug) => { /* ... */ });
export const const createPost: RemoteForm<{}, never>const createPost: RemoteForm<{}, never>createPost = form<v.ObjectSchema<{}, undefined>, never>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<never>): RemoteForm<{}, never> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{}, undefined>, never>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<never>): RemoteForm<{}, never> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vimport vv.object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({/* ... */}),
async (data: {}data: {}data) => {
// form logic goes here...
// Refresh `getPosts()` on the server, and send
// the data back with the result of `createPost`
// it's safe to throw away the promise from `refresh`,
// as the framework awaits it for us before serving the response
void const getPosts: (arg: void) => RemoteQuery<void>const getPosts: (arg: void) => RemoteQuery<void>getPosts().function refresh(): Promise<void>On the client, this function will re-fetch the query from the server.
On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
function refresh(): Promise<void>On the client, this function will re-fetch the query from the server.
On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
refresh();
// Redirect to the newly created page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
redirect(303, `/blog/${const slug: ""const slug: ""slug}`);
}
);
export const const updatePost: RemoteForm<{
id: string;
}, void>
const updatePost: RemoteForm<{
id: string;
}, void>
updatePost = form<v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined>, void>(validate: v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined>, fn: (data: {
id: string;
}, issue: {
id: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<void>): RemoteForm<{
id: string;
}, void> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined>, void>(validate: v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined>, fn: (data: {
id: string;
}, issue: {
id: (message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue;
} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => MaybePromise<void>): RemoteForm<{
id: string;
}, void> (+2 overloads)
Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vimport vv.object<{
readonly id: v.StringSchema<undefined>;
}>(entries: {
readonly id: v.StringSchema<undefined>;
}): v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{
readonly id: v.StringSchema<undefined>;
}>(entries: {
readonly id: v.StringSchema<undefined>;
}): v.ObjectSchema<{
readonly id: v.StringSchema<undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({ id: v.StringSchema<undefined>id: v.StringSchema<undefined>id: import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string() }),
async (post: {
id: string;
}
post: {
id: string;
}
post) => {
// form logic goes here...
const const result: anyconst result: anyresult = const externalApi: anyconst externalApi: anyexternalApi.update(post: {
id: string;
}
post: {
id: string;
}
post);
// The API already gives us the updated post,
// no need to refresh it, we can set it directly
const getPost: (arg: string) => RemoteQuery<void>const getPost: (arg: string) => RemoteQuery<void>getPost(post: {
id: string;
}post: {
id: string;
}post.id: stringid: stringid).function set(value: void): voidOn the client, this function will update the value of the query without re-fetching it.
On the server, this can be called in the context of a command or form and the specified data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
function set(value: void): voidOn the client, this function will update the value of the query without re-fetching it.
On the server, this can be called in the context of a command or form and the specified data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
const result: anyconst result: anyresult);
}
);Because queries are keyed based on their arguments, getPost(post.id).set(result) on the server knows to look up the matching getPost(id) on the client to update it. The same goes for getPosts().refresh() — it knows to look up getPosts() with no argument on the client.
Reconnecting live queries in mutations
Single-flight mutations can also reconnect query.live instances. In a form/command handler, call .reconnect() on the live query resource you want to reconnect:
import * as v from 'valibot';
import { form, query } from '$app/server';
export const getNotifications = query.live(v.string(), async function* (userId) {
while (true) {
yield await db.notifications(userId);
await wait(1000);
}
});
export const markAllRead = form(v.object({ userId: v.string() }), async ({ userId }) => {
// mutation logic...
getNotifications(userId).reconnect();
});This schedules a reconnect for the matching active client instances and applies it as part of the mutation response (i.e. in the same flight as the form/command result). You might need this if, for example, the command modifies a cookie that the live query needs to restart in order to capture.
Client-requested refreshes
Unfortunately, life isn’t always as simple as the preceding example. The server always knows which query functions to update, but it may not know which specific query instances to update. For example, if getPosts({ filter: 'author:santa' }) is rendered on the client, calling getPosts().refresh() in the server handler won’t update it. You’d need to call getPosts({ filter: 'author:santa' }).refresh() instead — but how could you know which specific combinations of filters are currently rendered on the client, especially if your query argument is more complicated than an object with just one key?
SvelteKit makes this easy by allowing the client to request that the server updates specific data using submit().updates (for form) or myCommand().updates (for command):
import type { type RemoteQueryUpdate = RemoteQuery<any> | RemoteLiveQuery<any> | RemoteQueryFunction<any, any, any> | RemoteLiveQueryFunction<any, any, any> | RemoteQueryOverridetype RemoteQueryUpdate = RemoteQuery<any> | RemoteLiveQuery<any> | RemoteQueryFunction<any, any, any> | RemoteLiveQueryFunction<any, any, any> | RemoteQueryOverrideRemoteQueryUpdate, type RemoteQuery<T> = RemoteResource<T> & {
set(value: T): void;
refresh(): Promise<void>;
withOverride(update: (current: T) => T): RemoteQueryOverride;
}
type RemoteQuery<T> = RemoteResource<T> & {
set(value: T): void;
refresh(): Promise<void>;
withOverride(update: (current: T) => T): RemoteQueryOverride;
}
RemoteQuery } from '@sveltejs/kit';
interface Post {}
declare function function submit(): Promise<any> & {
updates(...updates: RemoteQueryUpdate[]): Promise<any>;
}
function submit(): Promise<any> & {
updates(...updates: RemoteQueryUpdate[]): Promise<any>;
}
submit(): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<any> & {
function updates(...updates: RemoteQueryUpdate[]): Promise<any>function updates(...updates: RemoteQueryUpdate[]): Promise<any>updates(...updates: RemoteQueryUpdate[]updates: RemoteQueryUpdate[]updates: type RemoteQueryUpdate = RemoteQuery<any> | RemoteLiveQuery<any> | RemoteQueryFunction<any, any, any> | RemoteLiveQueryFunction<any, any, any> | RemoteQueryOverridetype RemoteQueryUpdate = RemoteQuery<any> | RemoteLiveQuery<any> | RemoteQueryFunction<any, any, any> | RemoteLiveQueryFunction<any, any, any> | RemoteQueryOverrideRemoteQueryUpdate[]): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<any>;
}
declare function function getPosts(args: {
filter: string;
}): RemoteQuery<Post[]>
function getPosts(args: {
filter: string;
}): RemoteQuery<Post[]>
getPosts(args: {
filter: string;
}
args: {
filter: string;
}
args: { filter: stringfilter: stringfilter: string }): type RemoteQuery<T> = RemoteResource<T> & {
set(value: T): void;
refresh(): Promise<void>;
withOverride(update: (current: T) => T): RemoteQueryOverride;
}
type RemoteQuery<T> = RemoteResource<T> & {
set(value: T): void;
refresh(): Promise<void>;
withOverride(update: (current: T) => T): RemoteQueryOverride;
}
RemoteQuery<Post[]>;
declare const const newPost: Postconst newPost: PostnewPost: Post;
// cut
await function submit(): Promise<any> & {
updates(...updates: RemoteQueryUpdate[]): Promise<any>;
}
function submit(): Promise<any> & {
updates(...updates: RemoteQueryUpdate[]): Promise<any>;
}
submit().function updates(...updates: RemoteQueryUpdate[]): Promise<any>function updates(...updates: RemoteQueryUpdate[]): Promise<any>updates(
// to request all active instances of getPosts
function getPosts(args: {
filter: string;
}): RemoteQuery<Post[]>
function getPosts(args: {
filter: string;
}): RemoteQuery<Post[]>
getPosts,
// to request a specific instance
function getPosts(args: {
filter: string;
}): RemoteQuery<Post[]>
function getPosts(args: {
filter: string;
}): RemoteQuery<Post[]>
getPosts({ filter: stringfilter: stringfilter: 'author:santa' }),
// to request a specific instance with an optimistic override
function getPosts(args: {
filter: string;
}): RemoteQuery<Post[]>
function getPosts(args: {
filter: string;
}): RemoteQuery<Post[]>
getPosts({ filter: stringfilter: stringfilter: 'author:santa' }).function withOverride(update: (current: Post[]) => Post[]): RemoteQueryOverrideTemporarily override a query's value during a single-flight mutation to provide optimistic updates.
<script>
import { getTodos, addTodo } from './todos.remote.js';
const todos = getTodos();
</script>
<form {...addTodo.enhance(async (form) => {
await form.submit().updates(
todos.withOverride((todos) => [...todos, { text: form.fields.text.value() }])
);
})}>
<input type="text" name="text" />
<button type="submit">Add Todo</button>
</form>
function withOverride(update: (current: Post[]) => Post[]): RemoteQueryOverrideTemporarily override a query's value during a single-flight mutation to provide optimistic updates.
<script>
import { getTodos, addTodo } from './todos.remote.js';
const todos = getTodos();
</script>
<form {...addTodo.enhance(async (form) => {
await form.submit().updates(
todos.withOverride((todos) => [...todos, { text: form.fields.text.value() }])
);
})}>
<input type="text" name="text" />
<button type="submit">Add Todo</button>
</form>
withOverride((posts: Post[]posts: Post[]posts) => [const newPost: Postconst newPost: PostnewPost, ...posts: Post[]posts: Post[]posts])
);It’s not enough to just request the updates from the client — you need to accept them from the server as well:
import * as import vimport vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error, function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
const const slug: ""const slug: ""slug = '';
const const post: {
id: string;
}
const post: {
id: string;
}
post = { id: stringid: stringid: '' };
const const externalApi: anyconst externalApi: anyexternalApi: any = '';
// cut
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query, function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form, function requested<Input, Output, Validated = Input>(query: RemoteQueryFunction<Input, Output, Validated>, limit: number): QueryRequestedResult<Validated, Output> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
function requested<Input, Output, Validated = Input>(query: RemoteQueryFunction<Input, Output, Validated>, limit: number): QueryRequestedResult<Validated, Output> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
requested } from '$app/server';
export const const getPosts: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>
const getPosts: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>
getPosts = query<v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined>, void>(schema: v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined>, fn: (arg: {
filter: string;
}) => MaybePromise<void>): RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}> (+2 overloads)
Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined>, void>(schema: v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined>, fn: (arg: {
filter: string;
}) => MaybePromise<void>): RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}> (+2 overloads)
Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(import vimport vv.object<{
readonly filter: v.StringSchema<undefined>;
}>(entries: {
readonly filter: v.StringSchema<undefined>;
}): v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{
readonly filter: v.StringSchema<undefined>;
}>(entries: {
readonly filter: v.StringSchema<undefined>;
}): v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({ filter: v.StringSchema<undefined>filter: v.StringSchema<undefined>filter: import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string() }), async ({ filter: stringfilter: stringfilter }) => { /* ... */ });
export const const createPost: RemoteForm<{}, never>const createPost: RemoteForm<{}, never>createPost = form<v.ObjectSchema<{}, undefined>, never>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<never>): RemoteForm<{}, never> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{}, undefined>, never>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<never>): RemoteForm<{}, never> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vimport vv.object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({/* ... */}),
async (data: {}data: {}data) => {
// form logic goes here...
for (const { const query: RemoteQuery<void>const query: RemoteQuery<void>query } of requested<{
filter: string;
}, void, {
filter: string;
}>(query: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>, limit: number): QueryRequestedResult<{
filter: string;
}, void> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
requested<{
filter: string;
}, void, {
filter: string;
}>(query: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>, limit: number): QueryRequestedResult<{
filter: string;
}, void> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
const getPosts: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>const getPosts: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>getPosts, 1)) {
void const query: RemoteQuery<void>const query: RemoteQuery<void>query.function refresh(): Promise<void>On the client, this function will re-fetch the query from the server.
On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
function refresh(): Promise<void>On the client, this function will re-fetch the query from the server.
On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response. Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response. Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
const slug: ""const slug: ""slug}`);
}
);import * as import vimport vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error, function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect: redirect will keep the request method
308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
const const slug: ""const slug: ""slug = '';
const const post: {
id: string;
}
const post: {
id: string;
}
post = { id: stringid: stringid: '' };
/** @type {any} */
const const externalApi: anyconst externalApi: anyexternalApi = '';
// cut
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query, function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form, function requested<Input, Output, Validated = Input>(query: RemoteQueryFunction<Input, Output, Validated>, limit: number): QueryRequestedResult<Validated, Output> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
function requested<Input, Output, Validated = Input>(query: RemoteQueryFunction<Input, Output, Validated>, limit: number): QueryRequestedResult<Validated, Output> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
requested } from '$app/server';
export const const getPosts: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>
const getPosts: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>
getPosts = query<v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined>, void>(schema: v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined>, fn: (arg: {
filter: string;
}) => MaybePromise<void>): RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}> (+2 overloads)
Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined>, void>(schema: v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined>, fn: (arg: {
filter: string;
}) => MaybePromise<void>): RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}> (+2 overloads)
Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(import vimport vv.object<{
readonly filter: v.StringSchema<undefined>;
}>(entries: {
readonly filter: v.StringSchema<undefined>;
}): v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{
readonly filter: v.StringSchema<undefined>;
}>(entries: {
readonly filter: v.StringSchema<undefined>;
}): v.ObjectSchema<{
readonly filter: v.StringSchema<undefined>;
}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({ filter: v.StringSchema<undefined>filter: v.StringSchema<undefined>filter: import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string() }), async ({ filter: stringfilter: stringfilter }) => { /* ... */ });
export const const createPost: RemoteForm<{}, never>const createPost: RemoteForm<{}, never>createPost = form<v.ObjectSchema<{}, undefined>, never>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<never>): RemoteForm<{}, never> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form<v.ObjectSchema<{}, undefined>, never>(validate: v.ObjectSchema<{}, undefined>, fn: (data: {}, issue: {} & ((message: string) => StandardSchemaV1<Input = unknown, Output = Input>.Issue)) => Promise<never>): RemoteForm<{}, never> (+2 overloads)Creates a form object that can be spread onto a <form> element.
See Remote functions for full documentation.
form(
import vimport vv.object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object<{}>(entries: {}): v.ObjectSchema<{}, undefined> (+1 overload)
export object
Creates an object schema.
Hint: This schema removes unknown entries. The output will only include the
entries you specify. To include unknown entries, use looseObject. To
return an issue for unknown entries, use strictObject. To include and
validate unknown entries, use objectWithRest.
object({/* ... */}),
async (data: {}data: {}data) => {
// form logic goes here...
for (const { const query: RemoteQuery<void>const query: RemoteQuery<void>query } of requested<{
filter: string;
}, void, {
filter: string;
}>(query: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>, limit: number): QueryRequestedResult<{
filter: string;
}, void> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
requested<{
filter: string;
}, void, {
filter: string;
}>(query: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>, limit: number): QueryRequestedResult<{
filter: string;
}, void> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
const getPosts: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>const getPosts: RemoteQueryFunction<{
filter: string;
}, void, {
filter: string;
}>getPosts, 1)) {
void const query: RemoteQuery<void>const query: RemoteQuery<void>query.function refresh(): Promise<void>On the client, this function will re-fetch the query from the server.
On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
function refresh(): Promise<void>On the client, this function will re-fetch the query from the server.
On the server, this can be called in the context of a command or form and the refreshed data will accompany the action response back to the client.
This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response. Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response. Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
const slug: ""const slug: ""slug}`);
}
);requested gives you access to the queries the client requested to refresh. Each entry is an { arg, query } object: arg is the value the query’s implementation function received — i.e. the argument after the schema has validated and (where applicable) transformed it — and query is a RemoteQuery already bound to the client’s original cache key, so calling query.refresh() / query.set(...) updates the correct client instance. If parsing an argument fails, that query will error, but the entire command will not fail. requested’s second parameter, limit, is the maximum number of items it will return. Any refresh requests beyond this limit will fail.
limitis required because the list of refresh requests is controlled by the client — each entry causes the server to validate an argument and usually re-fetch data, so an unbounded list is a denial-of-service risk. Choose a limit that reflects the worst case you’re willing to handle per request. You can passInfinityif you have explicitly decided to accept any number of refreshes, but it is not recommended.
Additionally, requested allows a simple shorthand when all you want to do is refresh the requested query instances:
import type { type RemoteQueryFunction<Input, Output, _Validated = Input> = (arg: undefined extends Input ? Input | void : Input) => RemoteQuery<Output>The return value of a remote query function. See Remote functions for full documentation.
The optional Validated generic parameter represents the argument type after the
query's schema has validated and (optionally) transformed it — this is the type the
query's implementation function receives on the server, and the type yielded by
requested. For queries declared
with Standard Schema it differs from Input when the
schema contains a transform (e.g. v.pipe(v.number(), v.transform(String)) has
Input = number but Validated = string). For 'unchecked' validators and queries
without arguments it defaults to Input.
type RemoteQueryFunction<Input, Output, _Validated = Input> = (arg: undefined extends Input ? Input | void : Input) => RemoteQuery<Output>The return value of a remote query function. See Remote functions for full documentation.
The optional Validated generic parameter represents the argument type after the
query's schema has validated and (optionally) transformed it — this is the type the
query's implementation function receives on the server, and the type yielded by
requested. For queries declared
with Standard Schema it differs from Input when the
schema contains a transform (e.g. v.pipe(v.number(), v.transform(String)) has
Input = number but Validated = string). For 'unchecked' validators and queries
without arguments it defaults to Input.
RemoteQueryFunction } from '@sveltejs/kit';
import { function requested<Input, Output, Validated = Input>(query: RemoteQueryFunction<Input, Output, Validated>, limit: number): QueryRequestedResult<Validated, Output> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
function requested<Input, Output, Validated = Input>(query: RemoteQueryFunction<Input, Output, Validated>, limit: number): QueryRequestedResult<Validated, Output> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
requested } from '$app/server';
declare const const getPosts: RemoteQueryFunction<any, any>const getPosts: RemoteQueryFunction<any, any>getPosts: type RemoteQueryFunction<Input, Output, _Validated = Input> = (arg: undefined extends Input ? Input | void : Input) => RemoteQuery<Output>The return value of a remote query function. See Remote functions for full documentation.
The optional Validated generic parameter represents the argument type after the
query's schema has validated and (optionally) transformed it — this is the type the
query's implementation function receives on the server, and the type yielded by
requested. For queries declared
with Standard Schema it differs from Input when the
schema contains a transform (e.g. v.pipe(v.number(), v.transform(String)) has
Input = number but Validated = string). For 'unchecked' validators and queries
without arguments it defaults to Input.
type RemoteQueryFunction<Input, Output, _Validated = Input> = (arg: undefined extends Input ? Input | void : Input) => RemoteQuery<Output>The return value of a remote query function. See Remote functions for full documentation.
The optional Validated generic parameter represents the argument type after the
query's schema has validated and (optionally) transformed it — this is the type the
query's implementation function receives on the server, and the type yielded by
requested. For queries declared
with Standard Schema it differs from Input when the
schema contains a transform (e.g. v.pipe(v.number(), v.transform(String)) has
Input = number but Validated = string). For 'unchecked' validators and queries
without arguments it defaults to Input.
RemoteQueryFunction<any, any>;
// cut
// this is the same as looping over the result and calling `void query.refresh()`.
await requested<any, any, any>(query: RemoteQueryFunction<any, any, any>, limit: number): QueryRequestedResult<any, any> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
requested<any, any, any>(query: RemoteQueryFunction<any, any, any>, limit: number): QueryRequestedResult<any, any> (+1 overload)Inside a remote command or form callback, returns an iterable
of { arg, query } entries for the query instances the client asked to refresh, up to
the supplied limit. Each query is a RemoteQuery bound to the original
client-side cache key, so refresh() / set() propagate correctly even when
the query's schema transforms the input. arg is the validated argument,
i.e. the value after the schema has run (so InferOutput<Schema> for queries
declared with a Standard Schema).
Arguments that fail validation or exceed limit are recorded as failures in
the response to the client.
See Client-requested refreshes
for usage in a remote command or form.
requested(const getPosts: RemoteQueryFunction<any, any>const getPosts: RemoteQueryFunction<any, any>getPosts, 1).refreshAll: () => Promise<void>Call refresh on all queries selected by this requested invocation.
This is identical to:
import { requested } from '$app/server';
for await (const { query } of requested(getPost, ...)) {
void query.refresh();
}
refreshAll: () => Promise<void>Call refresh on all queries selected by this requested invocation.
This is identical to:
import { requested } from '$app/server';
for await (const { query } of requested(getPost, ...)) {
void query.refresh();
}
refreshAll();Why does the command have to name every query it’s willing to refresh? Two reasons:
- Bundle size. If a command could implicitly refresh any query in your app, SvelteKit would have to include every query’s code in the command’s server bundle, because it can’t know ahead of time which ones will be called.
- Denial-of-service. Any malicious user can inspect their network tab to discover which queries your app uses, then POST a command with a client-supplied list of thousands of refreshes. The only defence is for the server handler to declare which queries it is willing to refresh — and in what quantity (hence the required
limit).
prerender
The prerender function is similar to query, except that it will be invoked at build time to prerender the result. Use this for data that changes at most once per redeployment.
// @filename: ambient.d.ts
declare module '$lib/server/database' {
export function function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql(strings: TemplateStringsArraystrings: TemplateStringsArraystrings: TemplateStringsArray, ...values: any[]values: any[]values: any[]): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<any[]>;
}
// @filename: index.js
// cut
import { function prerender<Output>(fn: () => MaybePromise<Output>, options?: {
inputs?: RemotePrerenderInputsGenerator<void>;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, Output> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender } from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database';
export const const getPosts: RemotePrerenderFunction<void, any[]>getPosts = prerender<any[]>(fn: () => MaybePromise<any[]>, options?: {
inputs?: RemotePrerenderInputsGenerator<void>;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, any[]> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender(async () => {
const const posts: any[]posts = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql`
SELECT title, slug
FROM post
ORDER BY published_at
DESC
`;
return const posts: any[]posts;
});You can use prerender functions on pages that are otherwise dynamic, allowing for partial prerendering of your data. This results in very fast navigation, since prerendered data can live on a CDN along with your other static assets.
In the browser, prerendered data is saved using the Cache API. This cache survives page reloads, and will be cleared when the user first visits a new deployment of your app.
Prerender arguments
As with queries, prerender functions can accept an argument, which should be validated with a Standard Schema:
// @filename: ambient.d.ts
declare module '$lib/server/database' {
export function function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql(strings: TemplateStringsArraystrings: TemplateStringsArraystrings: TemplateStringsArray, ...values: any[]values: any[]values: any[]): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<any[]>;
}
// @filename: index.js
// cut
import * as import vv from 'valibot';
import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error } from '@sveltejs/kit';
import { function prerender<Output>(fn: () => MaybePromise<Output>, options?: {
inputs?: RemotePrerenderInputsGenerator<void>;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, Output> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender } from '$app/server';
import * as module "$lib/server/database"db from '$lib/server/database';
export const const getPosts: RemotePrerenderFunction<void, void>getPosts = prerender<void>(fn: () => MaybePromise<void>, options?: {
inputs?: RemotePrerenderInputsGenerator<void>;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, void> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender(async () => { /* ... */ });
export const const getPost: RemotePrerenderFunction<string, any>getPost = prerender<v.StringSchema<undefined>, any>(schema: v.StringSchema<undefined>, fn: (arg: string) => any, options?: {
inputs?: RemotePrerenderInputsGenerator<string> | undefined;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<string, any> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender(import vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(), async (slug: stringslug) => {
const [const post: anypost] = await module "$lib/server/database"db.function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>sql`
SELECT * FROM post
WHERE slug = ${slug: stringslug}
`;
if (!const post: anypost) function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
error(404, 'Not found');
return const post: anypost;
});Any calls to getPost(...) found by SvelteKit’s crawler while prerendering pages will be saved automatically, but you can also specify which values it should be called with using the inputs option:
import * as import vimport vv from 'valibot';
import { function prerender<Output>(fn: () => MaybePromise<Output>, options?: {
inputs?: RemotePrerenderInputsGenerator<void>;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, Output> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function prerender<Output>(fn: () => MaybePromise<Output>, options?: {
inputs?: RemotePrerenderInputsGenerator<void>;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, Output> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender } from '$app/server';
// cut
export const const getPost: RemotePrerenderFunction<string, void>const getPost: RemotePrerenderFunction<string, void>getPost = prerender<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>, options?: {
inputs?: RemotePrerenderInputsGenerator<string> | undefined;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<string, void> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>, options?: {
inputs?: RemotePrerenderInputsGenerator<string> | undefined;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<string, void> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender(
import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(),
async (slug: stringslug: stringslug) => { /* ... */ },
{
inputs?: RemotePrerenderInputsGenerator<string> | undefinedinputs?: RemotePrerenderInputsGenerator<string> | undefinedinputs: () => [
'first-post',
'second-post',
'third-post'
]
}
);By default, prerender functions are excluded from your server bundle, which means that you cannot call them with any arguments that were not prerendered. You can set dynamic: true to change this behaviour:
import * as import vimport vv from 'valibot';
import { function prerender<Output>(fn: () => MaybePromise<Output>, options?: {
inputs?: RemotePrerenderInputsGenerator<void>;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, Output> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function prerender<Output>(fn: () => MaybePromise<Output>, options?: {
inputs?: RemotePrerenderInputsGenerator<void>;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<void, Output> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender } from '$app/server';
// cut
export const const getPost: RemotePrerenderFunction<string, void>const getPost: RemotePrerenderFunction<string, void>getPost = prerender<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>, options?: {
inputs?: RemotePrerenderInputsGenerator<string> | undefined;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<string, void> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender<v.StringSchema<undefined>, void>(schema: v.StringSchema<undefined>, fn: (arg: string) => MaybePromise<void>, options?: {
inputs?: RemotePrerenderInputsGenerator<string> | undefined;
dynamic?: boolean;
} | undefined): RemotePrerenderFunction<string, void> (+2 overloads)
Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
prerender(
import vimport vv.function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
function string(): v.StringSchema<undefined> (+1 overload)
export string
Creates a string schema.
string(),
async (slug: stringslug: stringslug) => { /* ... */ },
{
dynamic?: boolean | undefineddynamic?: boolean | undefineddynamic: true,
inputs?: RemotePrerenderInputsGenerator<string> | undefinedinputs?: RemotePrerenderInputsGenerator<string> | undefinedinputs: () => [
'first-post',
'second-post',
'third-post'
]
}
);Handling validation errors
As long as you’re not passing invalid data to your remote functions, there are only two reasons why the argument passed to a command, query or prerender function would fail validation:
- the function signature changed between deployments, and some users are currently on an older version of your app
- someone is trying to attack your site by poking your exposed endpoints with bad data
In the second case, we don’t want to give the attacker any help, so SvelteKit will generate a generic 400 Bad Request response. You can control the message by implementing the handleValidationError server hook, which, like handleError, must return an App.Error (which defaults to { message: string }):
import type { type HandleValidationError<Issue extends StandardSchemaV1.Issue = StandardSchemaV1.Issue> = (input: {
issues: Issue[];
event: RequestEvent;
}) => MaybePromise<App.Error>
The handleValidationError hook runs when the argument to a remote function fails validation.
It will be called with the validation issues and the event, and must return an object shape that matches App.Error.
type HandleValidationError<Issue extends StandardSchemaV1.Issue = StandardSchemaV1.Issue> = (input: {
issues: Issue[];
event: RequestEvent;
}) => MaybePromise<App.Error>
The handleValidationError hook runs when the argument to a remote function fails validation.
It will be called with the validation issues and the event, and must return an object shape that matches App.Error.
HandleValidationError } from '@sveltejs/kit';
export const const handleValidationError: HandleValidationErrorconst handleValidationError: HandleValidationErrorhandleValidationError: type HandleValidationError<Issue extends StandardSchemaV1.Issue = StandardSchemaV1.Issue> = (input: {
issues: Issue[];
event: RequestEvent;
}) => MaybePromise<App.Error>
The handleValidationError hook runs when the argument to a remote function fails validation.
It will be called with the validation issues and the event, and must return an object shape that matches App.Error.
type HandleValidationError<Issue extends StandardSchemaV1.Issue = StandardSchemaV1.Issue> = (input: {
issues: Issue[];
event: RequestEvent;
}) => MaybePromise<App.Error>
The handleValidationError hook runs when the argument to a remote function fails validation.
It will be called with the validation issues and the event, and must return an object shape that matches App.Error.
HandleValidationError = ({ event: RequestEvent<Record<string, string>, string | null>event: RequestEvent<Record<string, string>, string | null>event, issues: StandardSchemaV1.Issue[]issues: StandardSchemaV1.Issue[]issues }) => {
return {
App.Error.message: stringApp.Error.message: stringmessage: 'Nice try, hacker!'
};
};/** @type {import('@sveltejs/kit').HandleValidationError} */
export function function handleValidationError(input: {
issues: StandardSchemaV1<Input = unknown, Output = Input>.Issue[];
event: RequestEvent;
}): MaybePromise<App.Error>
function handleValidationError(input: {
issues: StandardSchemaV1<Input = unknown, Output = Input>.Issue[];
event: RequestEvent;
}): MaybePromise<App.Error>
handleValidationError({ event: RequestEvent<Record<string, string>, string | null>event: RequestEvent<Record<string, string>, string | null>event, issues: StandardSchemaV1.Issue[]issues: StandardSchemaV1.Issue[]issues }) {
return {
App.Error.message: stringApp.Error.message: stringmessage: 'Nice try, hacker!'
};
}If you know what you’re doing and want to opt out of validation, you can pass the string 'unchecked' in place of a schema:
import { function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query } from '$app/server';
export const const getStuff: RemoteQueryFunction<{
id: string;
}, void>
const getStuff: RemoteQueryFunction<{
id: string;
}, void>
getStuff = query<{
id: string;
}, void>(validate: "unchecked", fn: (arg: {
id: string;
}) => MaybePromise<void>): RemoteQueryFunction<{
id: string;
}, void> (+2 overloads)
Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<{
id: string;
}, void>(validate: "unchecked", fn: (arg: {
id: string;
}) => MaybePromise<void>): RemoteQueryFunction<{
id: string;
}, void> (+2 overloads)
Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query('unchecked', async ({ id: stringid: stringid }: { id: stringid: stringid: string }) => {
// the shape might not actually be what TypeScript thinks
// since bad actors might call this function with other arguments
});Using getRequestEvent
Inside query, form and command you can use getRequestEvent to get the current RequestEvent object. This makes it easy to build abstractions for interacting with cookies, for example:
// @filename: ambient.d.ts
interface User {
User.name: stringUser.name: stringname: string;
User.avatar: stringUser.avatar: stringavatar: string;
}
declare module '$lib/server/database' {
export function function findUser(sessionId: string | undefined): Promise<User | null>function findUser(sessionId: string | undefined): Promise<User | null>findUser(sessionId: string | undefinedsessionId: string | undefinedsessionId: string | undefined): interface Promise<T>Represents the completion of an asynchronous operation
interface Promise<T>Represents the completion of an asynchronous operation
Promise<User | null>;
}
// @filename: index.js
// cut
import { function getRequestEvent(): RequestEventReturns the current RequestEvent. Can be used inside server hooks, server load functions, actions, and endpoints (and functions called by them).
In environments without AsyncLocalStorage, this must be called synchronously (i.e. not after an await).
function getRequestEvent(): RequestEventReturns the current RequestEvent. Can be used inside server hooks, server load functions, actions, and endpoints (and functions called by them).
In environments without AsyncLocalStorage, this must be called synchronously (i.e. not after an await).
getRequestEvent, function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
function query<Output>(fn: () => MaybePromise<Output>): RemoteQueryFunction<void, Output> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query } from '$app/server';
import { function findUser(sessionId: string | undefined): Promise<User | null>function findUser(sessionId: string | undefined): Promise<User | null>findUser } from '$lib/server/database';
export const const getProfile: RemoteQueryFunction<void, {
name: string;
avatar: string;
} | null>
const getProfile: RemoteQueryFunction<void, {
name: string;
avatar: string;
} | null>
getProfile = query<{
name: string;
avatar: string;
} | null>(fn: () => MaybePromise<{
name: string;
avatar: string;
} | null>): RemoteQueryFunction<void, {
name: string;
avatar: string;
} | null> (+2 overloads)
Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<{
name: string;
avatar: string;
} | null>(fn: () => MaybePromise<{
name: string;
avatar: string;
} | null>): RemoteQueryFunction<void, {
name: string;
avatar: string;
} | null> (+2 overloads)
Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(async () => {
const const user: User | nullconst user: User | nulluser = await const getUser: (arg: void) => RemoteQuery<User | null>const getUser: (arg: void) => RemoteQuery<User | null>getUser();
return const user: User | nullconst user: User | nulluser && {
name: stringname: stringname: const user: Userconst user: Useruser.User.name: stringUser.name: stringname,
avatar: stringavatar: stringavatar: const user: Userconst user: Useruser.User.avatar: stringUser.avatar: stringavatar
};
});
// this query could be called from multiple places, but
// the function will only run once per request
const const getUser: RemoteQueryFunction<void, User | null>const getUser: RemoteQueryFunction<void, User | null>getUser = query<User | null>(fn: () => MaybePromise<User | null>): RemoteQueryFunction<void, User | null> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query<User | null>(fn: () => MaybePromise<User | null>): RemoteQueryFunction<void, User | null> (+2 overloads)Creates a remote query. When called from the browser, the function will be invoked on the server via a fetch call.
See Remote functions for full documentation.
query(async () => {
const { const cookies: CookiesGet or set cookies related to the current request
const cookies: CookiesGet or set cookies related to the current request
cookies } = function getRequestEvent(): RequestEventReturns the current RequestEvent. Can be used inside server hooks, server load functions, actions, and endpoints (and functions called by them).
In environments without AsyncLocalStorage, this must be called synchronously (i.e. not after an await).
function getRequestEvent(): RequestEventReturns the current RequestEvent. Can be used inside server hooks, server load functions, actions, and endpoints (and functions called by them).
In environments without AsyncLocalStorage, this must be called synchronously (i.e. not after an await).
getRequestEvent();
return await function findUser(sessionId: string | undefined): Promise<User | null>function findUser(sessionId: string | undefined): Promise<User | null>findUser(const cookies: CookiesGet or set cookies related to the current request
const cookies: CookiesGet or set cookies related to the current request
cookies.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefinedGets a cookie that was previously set with cookies.set, or from the request headers.
Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefinedGets a cookie that was previously set with cookies.set, or from the request headers.
get('session_id'));
});Note that some properties of RequestEvent are different inside remote functions:
- you cannot set headers (other than writing cookies, and then only inside
formandcommandfunctions) route,paramsandurlrelate to the page the remote function was called from, not the URL of the endpoint SvelteKit creates for the remote function. Never use them to determine whether or not a user is authorized to access certain data, as these values are part of the request which could be manipulated. Queries are also not re-run when the user navigates (unless the argument to the query changes as a result of navigation), and so you should be mindful of how you use these values.
Redirects
Inside query, form and prerender functions it is possible to use the redirect(...) function. It is not possible inside command functions, as you should avoid redirecting here. (If you absolutely have to, you can return a { redirect: location } object and deal with it in the client.)