Skip to main content

@sveltejs/kit/hooks

import { sequence } from '@sveltejs/kit/hooks';

sequence

A helper function for sequencing multiple handle calls in a middleware-like manner. The behavior for the handle options is as follows:

  • transformPageChunk is applied in reverse order and merged
  • preload is applied in forward order, the first option “wins” and no preload options after it are called
  • filterSerializedResponseHeaders behaves the same as preload
src/hooks.server
import { sequence } from '@sveltejs/kit/hooks';
/** @type {import('@sveltejs/kit/hooks').Handle} */async function first({ event, resolve }) {
	console.log('first pre-processing');
	const result = await resolve(event, {
		transformPageChunk: ({ html }) => {
			// transforms are applied in reverse order			console.log('first transform');
			return html;
		},
		preload: () => {
			// this one wins as it's the first defined in the chain			console.log('first preload');
			return true;
		}
	});
	console.log('first post-processing');
	return result;
}
/** @type {import('@sveltejs/kit/hooks').Handle} */async function second({ event, resolve }) {
	console.log('second pre-processing');
	const result = await resolve(event, {
		transformPageChunk: ({ html }) => {
			console.log('second transform');
			return html;
		},
		preload: () => {
			console.log('second preload');
			return true;
		},
		filterSerializedResponseHeaders: () => {
			// this one wins as it's the first defined in the chain			console.log('second filterSerializedResponseHeaders');
			return true;
		}
	});
	console.log('second post-processing');
	return result;
}

export const handle = sequence(first, second);
import { sequence } from '@sveltejs/kit/hooks';
import type { Handle } from '@sveltejs/kit/hooks';

const first: Handle = async ({ event, resolve }) => {
	console.log('first pre-processing');
	const result = await resolve(event, {
		transformPageChunk: ({ html }) => {
			// transforms are applied in reverse order			console.log('first transform');
			return html;
		},
		preload: () => {
			// this one wins as it's the first defined in the chain			console.log('first preload');
			return true;
		}
	});
	console.log('first post-processing');
	return result;
};

const second: Handle = async ({ event, resolve }) => {
	console.log('second pre-processing');
	const result = await resolve(event, {
		transformPageChunk: ({ html }) => {
			console.log('second transform');
			return html;
		},
		preload: () => {
			console.log('second preload');
			return true;
		},
		filterSerializedResponseHeaders: () => {
			// this one wins as it's the first defined in the chain			console.log('second filterSerializedResponseHeaders');
			return true;
		}
	});
	console.log('second post-processing');
	return result;
};

export const handle = sequence(first, second);

The example above would print:

first pre-processing
first preload
second pre-processing
second filterSerializedResponseHeaders
second transform
first transform
second post-processing
first post-processing

Calling resolve invokes the next handler in the sequence (or SvelteKit itself, if it is the last one). To pass data between handlers, use event.locals.

function sequence(...handlers: Handle[]): Handle;

CaughtError

The error passed to the handleError hooks. Use the kind discriminant to distinguish errors from your app (thrown with the error helper), errors generated by SvelteKit itself (such as 404s), validation errors, and unknown errors (thrown by your code, or code it calls).

type CaughtError<
	Issue extends StandardSchemaV1.Issue =
		StandardSchemaV1.Issue
> =
	| {
			[Kind in keyof CaughtErrorMap]: {
				/** Identifies the category and origin of the error */
				kind: Kind;
				/** The caught error. Its type depends on `kind` */
				error: CaughtErrorMap[Kind];
				/** Only present for validation errors */
				issues?: undefined;
			};
	  }[keyof CaughtErrorMap]
	| ValidationCaughtError<Issue>;

ClientCaughtError

The error passed to the client-side handleError hook.

type ClientCaughtError = Exclude<
	CaughtError,
	{ kind: 'validation' }
>;

ClientInit

Available since 2.10.0

The init will be invoked once the app starts in the browser

type ClientInit = () => MaybePromise<void>;

Handle

The handle hook runs every time the SvelteKit server receives a request and determines the response. It receives an event object representing the request and a function called resolve, which renders the route and generates a Response. This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing routes programmatically, for example).

type Handle = (input: {
	event: RequestEvent;
	resolve: (
		event: RequestEvent,
		opts?: ResolveOptions
	) => Promise<Response>;
}) => MaybePromise<Response>;

HandleClientError

The client-side handleError hook runs for every error thrown while navigating, except redirects. Errors that were already transformed by the server-side hook are not passed to it a second time.

The kind property discriminates between app errors (thrown with the error helper), framework errors (generated by SvelteKit itself, such as 404s) and unknown errors (thrown by your code, or code it calls).

The hook returns an object matching App.Error, in which status and message are optional — return them only to override the defaults. Omitted properties are inherited from the caught error: the body passed to error(...) for app errors, the status and safe message for framework errors, and 500 / 'Internal Error' for unknown errors. Return nothing to keep the defaults entirely (if you augment App.Error with required properties, you must return those).

Make sure that this function never throws an error.

type HandleClientError = (
	input: ClientCaughtError & { event: NavigationEvent }
) => MaybePromise<
	| AppErrorWithOptionalDefaults
	| VoidIfNoRequiredAppErrorProperties
>;

HandleFetch

The handleFetch hook allows you to modify (or replace) the result of an event.fetch call that runs on the server (or during prerendering) inside an endpoint, load, action, handle, handleError or reroute.

type HandleFetch = (input: {
	event: RequestEvent;
	request: Request;
	fetch: typeof fetch;
}) => MaybePromise<Response>;

HandleServerError

The server-side handleError hook runs for every error thrown while responding to a request, except redirects.

The kind property discriminates between app errors (thrown with the error helper), framework errors (generated by SvelteKit itself, such as 404s), validation errors (caused by invalid remote function arguments) and unknown errors (thrown by your code, or code it calls).

The hook returns an object matching App.Error, in which status and message are optional — return them only to override the defaults. Omitted properties are inherited from the caught error: the body passed to error(...) for app errors, the status and safe message for framework and validation errors, and 500 / 'Internal Error' for unknown errors. Return nothing to keep the defaults entirely (if you augment App.Error with required properties, you must return those).

Make sure that this function never throws an error.

type HandleServerError<
	Issue extends StandardSchemaV1.Issue =
		StandardSchemaV1.Issue
> = (
	input: CaughtError<Issue> & { event: RequestEvent }
) => MaybePromise<
	| AppErrorWithOptionalDefaults
	| VoidIfNoRequiredAppErrorProperties
>;

Reroute

Available since 2.3.0

The reroute hook allows you to modify the URL before it is used to determine which route to render.

type Reroute = (event: {
	url: URL;
	fetch: typeof fetch;
}) => MaybePromise<void | string>;

ResolveOptions

interface ResolveOptions {/*…*/}
transformPageChunk?: (input: { html: string; done: boolean }) => MaybePromise<string | undefined>;
  • input the html chunk and the info if this is the last chunk

Applies custom transforms to HTML. If done is true, it’s the final chunk. Chunks are not guaranteed to be well-formed HTML (they could include an element’s opening tag but not its closing tag, for example) but they will always be split at sensible boundaries such as %sveltekit.head% or layout/page components.

filterSerializedResponseHeaders?: (name: string, value: string) => boolean;
  • name header name
  • value header value

Determines which headers should be included in serialized responses when a load function loads a resource with fetch. By default, none will be included.

preload?: (
	input:
		| { type: 'css' | 'js' | 'asset'; path: string }
		| { type: 'font'; path: string; filename: string }
) => boolean;
  • input the type of the file and its path

Determines which files should be preloaded. Files are preloaded via <link> tags added to the <head> tag; if output.linkHeaderPreload is enabled, dynamically rendered pages use the Link response header instead. By default, js and css files will be preloaded.

For font files, input also has a filename property, the source file’s pathname relative to the project root, so that a filter can match on it instead of the hashed path. js and css files are bundled and have no single source file name.

ServerInit

Available since 2.10.0

The init will be invoked before the server responds to its first request

type ServerInit = () => MaybePromise<void>;

Transport

Available since 2.11.0

The transport hook allows you to transport custom types across the server/client boundary.

Each transporter has a pair of encode and decode functions. On the server, encode determines whether a value is an instance of the custom type and, if so, returns a non-falsy encoding of the value which can be an object or an array (or false otherwise).

In the browser, decode turns the encoding back into an instance of the custom type.

import type { Transport } from '@sveltejs/kit/hooks';

declare class MyCustomType {
	data: any
}
// hooks.jsexport const transport: Transport = {
	MyCustomType: {
		encode: (value) => value instanceof MyCustomType && [value.data],
		decode: ([data]) => new MyCustomType(data)
	}
};
type Transport = Record<string, Transporter>;

Transporter

A member of the transport hook.

interface Transporter<
	T = any,
	U =
		any /* minus falsy values, but we can't properly express that */
> {/*…*/}
encode: (value: T) => false | U;
decode: (data: U) => T;

Edit this page on GitHub llms.txt