Skip to main content

Hooks

Edit this page on GitHub

An optional src/hooks.js (or src/hooks.ts, or src/hooks/index.js) file exports three functions, all optional, that run on the server — handle, handleError and externalFetch.

The location of this file can be configured as config.kit.files.hooks

handlepermalink

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 bypass SvelteKit entirely (for implementing routes programmatically, for example).

src/hooks.js
ts
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
if (event.url.pathname.startsWith('/custom')) {
return new Response('custom response');
}
 
const response = await resolve(event);
return response;
}

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

If unimplemented, defaults to ({ event, resolve }) => resolve(event). To add custom data to the request, which is passed to handlers in +server.js and server-only load functions, populate the event.locals object, as shown below.

src/hooks.js
ts
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
event.locals.user = await getUserInformation(event.request.headers.get('cookie'));
 
const response = await resolve(event);
response.headers.set('x-custom-header', 'potato');
 
return response;
}

You can add call multiple handle functions 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:

  • ssr: boolean (default true) — if false, renders an empty 'shell' page instead of server-side rendering
  • 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.
src/hooks.js
ts
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
const response = await resolve(event, {
ssr: !event.url.pathname.startsWith('/admin'),
transformPageChunk: ({ html }) => html.replace('old', 'new')
});
 
return response;
}

Disabling server-side rendering effectively turns your SvelteKit app into a single-page app or SPA. In most situations this is not recommended (see appendix). Consider whether it's truly appropriate to disable it, and do so selectively rather than for all requests.

handleErrorpermalink

If an error is thrown during loading or rendering, this function will be called with the error and the event that caused it. This allows you to send data to an error tracking service, or to customise the formatting before printing the error to the console.

During development, if an error occurs because of a syntax error in your Svelte code, a frame property will be appended highlighting the location of the error.

If unimplemented, SvelteKit will log the error with default formatting.

src/hooks.js
ts
/** @type {import('@sveltejs/kit').HandleError} */
export function handleError({ error, event }) {
// example integration with https://sentry.io/
Sentry.captureException(error, { event });
}

handleError is only called for unexpected errors. It is not called for errors created with the error function imported from @sveltejs/kit, as these are expected errors.

externalFetchpermalink

This function allows you to modify (or replace) a fetch request for an external resource that happens inside a load function that runs on the server (or during pre-rendering).

For example, your load function might make a request to a public URL like https://api.yourapp.com when the user performs a client-side navigation to the respective page, but during SSR it might make sense to hit the API directly (bypassing whatever proxies and load balancers sit between it and the public internet).

ts
/** @type {import('@sveltejs/kit').ExternalFetch} */
export async function externalFetch(request) {
if (request.url.startsWith('https://api.yourapp.com/')) {
// clone the original request, but change the URL
request = new Request(
request.url.replace('https://api.yourapp.com/', 'http://localhost:9999/'),
request
);
}
 
return fetch(request);
}
previous Loading data
next Modules
We stand with Ukraine. Donate → We stand with Ukraine. Petition your leaders. Show your support.