Skip to main content

Hooks

‘Hooks’ are app-wide functions you declare that SvelteKit will call in response to specific events, giving you fine-grained control over the framework’s behaviour.

There are three hooks files, all optional:

  • src/hooks.server.js — your app’s server hooks
  • src/hooks.client.js — your app’s client hooks
  • src/hooks.js — your app’s hooks that run on both the client and server

Code in these modules will run when the application starts up, making them useful for initializing database clients and so on.

handle

Can be added to src/hooks.server.js

This function runs every time the SvelteKit server receives a request — whether that happens while the app is running, or during prerendering — 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 implement a middleware (for rejecting rate-limited requests, for example).

src/hooks.server
import { building } from '$app/env';
import { isRateLimited } from '#lib/server/rate-limit.js';

/** @type {import('@sveltejs/kit/hooks').Handle} */
export async function handle({ event, resolve }) {
	if (!building && (await isRateLimited(event.getClientAddress()))) {
		return new Response('Too many requests', { status: 429 });
	}

	const response = await resolve(event);
	return response;
}
import { building } from '$app/env';
import { isRateLimited } from '#lib/server/rate-limit.js';
import type { Handle } from '@sveltejs/kit/hooks';

export const handle: Handle = async ({ event, resolve }) => {
	if (!building && (await isRateLimited(event.getClientAddress()))) {
		return new Response('Too many requests', { status: 429 });
	}

	const response = await resolve(event);
	return response;
};

Requests for static assets — which includes pages that were already prerendered — are not handled by SvelteKit.

If the handle hook runs as part of a remote function request initiated by the client, route, params and url relate 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.

If unimplemented, defaults to ({ event, resolve }) => resolve(event).

During prerendering, SvelteKit crawls your pages for links and renders each route it finds. Rendering the route invokes the handle function (and all other route dependencies, like load). If you need to exclude some code from running during this phase, check that the app is not building beforehand.

You can define multiple handle functions and execute them with the sequence helper function.

resolve also supports a second, optional parameter that gives you more control over how the response will be rendered. That parameter is an object that can have the following fields:

  • transformPageChunk(opts: { html: string, done: boolean }): MaybePromise<string | undefined> — 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 — 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: 'js' | 'css' | 'asset', path: string } | { type: 'font', path: string, filename: string }): boolean — 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. The method is called with each file that was found at build time while constructing the code chunks — so if you for example have import './styles.css in your +page.svelte, preload will be called with the resolved path to that CSS file when visiting that page. Note that in dev mode preload is not called, since it depends on analysis that happens at build time. Preloading can improve performance by downloading assets sooner, but it can also hurt if too much is downloaded unnecessarily. By default, js and css files will be preloaded. asset files are not preloaded at all currently, but we may add this later after evaluating feedback. 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.
src/hooks.server
/** @type {import('@sveltejs/kit/hooks').Handle} */
export async function handle({ event, resolve