Hooks
Hooks are SvelteKit’s middleware layer: server-side functions that run for every request (or every unexpected error), defined in src/hooks.server.js (or .ts).
The handle hook
handle wraps every request. You call resolve() to get the response, and can rewrite it on the way out:
/// file: src/hooks.server.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
const response = await resolve(event, {
transformPageChunk: ({ html }) => html.replace('%lang%', 'en'),
filterSerializedResponseHeaders: (name) => name.startsWith('x-'),
preload: ({ type }) => type === 'js' || type === 'css',
});
response.headers.set('x-request-id', crypto.randomUUID());
return response;
}
eventcarries the URL, params, cookies, locals, andgetClientAddress()transformPageChunkrewrites HTML as it streams (chunked, so stateful transforms need care)filterSerializedResponseHeaderscontrols which headers survive into load-function fetchesresolve()never throws; errors thrown insidehandleitself are fatal
Use sequence() from @sveltejs/kit/hooks to compose multiple handle functions (auth, then logging, then request-id).
handleError
Runs on unexpected errors, both for SSR and in remote functions:
/** @type {import('@sveltejs/kit').HandleServerError} */
export function handleError({ event, status, message, error }) {
log.error(event.route.id, error);
return { message: 'Something went wrong' };
}
Remote functions add a validation flavor: when a remote function receives invalid input, the hook is called with kind: 'validation' and the validation issues:
/** @type {import('@sveltejs/kit').HandleServerError} */
export function handleError({ kind, issues }) {
if (kind === 'validation') {
console.error(issues);
return { message: 'Invalid input' };
}
}
Gotcha: whatever
handleErrorreturns is shown to the client. Never echo raw error messages or validation issue details you would not publish.
What hooks are not
They are not the place for route logic (that belongs in +page.server.js / remote functions), and they do not run for prerendered pages served statically. Cache headers, auth redirects, and A/B flags are the classic residents; see Prerendering and Caching for the cache-header case.