08 - Hooks
What are Hooks?
Hooks are functions that run on every request, letting you add global behavior — authentication, logging, error handling, etc. They live in special files at the src/ root.
| File | Runs on | Purpose |
|---|---|---|
src/hooks.server.ts |
Server | Auth, logging, modify requests/responses |
src/hooks.client.ts |
Client | Client-side error handling |
Server Hooks
handle — Runs on Every Request
The main hook. It receives every request and must call resolve(event) to continue processing. You can modify the request before and the response after:
// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
// BEFORE: runs before the route handler
console.log(`Request: ${event.url.pathname}`);
// Add data to event.locals — available in load functions and actions
event.locals.user = await getUser(event.cookies);
const response = await resolve(event); // process the route
// AFTER: runs after the route handler
response.headers.set('X-Custom-Header', 'value');
return response;
};event.locals is a per-request object you can attach data to. It's available in all load functions and form actions for that request.
handleFetch — Modify Server-Side Fetch
Intercept fetch() calls made in load functions during SSR:
// src/hooks.server.ts
import type { HandleFetch } from '@sveltejs/kit';
export const handleFetch: HandleFetch = async ({ request, fetch }) => {
// Add auth headers to API calls made during SSR
if (request.url.startsWith('https://api.example.com')) {
request.headers.set('Authorization', 'Bearer token');
}
return fetch(request);
};handleError — Handle Unexpected Errors
Catches unhandled errors on the server. Use for logging — the returned object becomes $page.error:
// src/hooks.server.ts
import type { HandleServerError } from '@sveltejs/kit';
export const handleError: HandleServerError = async ({ error, event }) => {
console.error('Server error:', error);
return {
message: 'Something went wrong' // shown to the user via +error.svelte
};
};Client Hooks
handleError — Client-Side Errors
Same concept as server, but for errors that happen in the browser:
// src/hooks.client.ts
import type { HandleClientError } from '@sveltejs/kit';
export const handleError: HandleClientError = async ({ error }) => {
console.error('Client error:', error);
return {
message: 'An error occurred'
};
};Authentication Example
A common pattern — check for a session cookie, load the user, and protect routes:
// src/hooks.server.ts
import { redirect } from '@sveltejs/kit';
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
// 1. Check session cookie
const session = event.cookies.get('session');
// 2. Load user if session exists
if (session) {
event.locals.user = await db.getUserBySession(session);
}
// 3. Protect routes — redirect to login if not authenticated
if (event.url.pathname.startsWith('/dashboard')) {
if (!event.locals.user) {
redirect(303, '/login');
}
}
return resolve(event);
};Then access locals.user in any load function or action:
// src/routes/+layout.server.ts
import type { LayoutServerLoad } from './$types';
export const load: LayoutServerLoad = async ({ locals }) => {
return { user: locals.user }; // available in all pages
};Sequencing Multiple Hooks
Use sequence() to compose multiple handle functions — they run in order:
// src/hooks.server.ts
import { sequence } from '@sveltejs/kit/hooks';
import type { Handle } from '@sveltejs/kit';
const auth: Handle = async ({ event, resolve }) => {
event.locals.user = await getUser(event);
return resolve(event);
};
const logger: Handle = async ({ event, resolve }) => {
console.log(event.url.pathname);
return resolve(event);
};
export const handle = sequence(auth, logger); // auth runs first, then loggerTransform HTML
Modify the rendered HTML before sending it to the client:
// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
const response = await resolve(event, {
transformPageChunk: ({ html }) => {
return html.replace('%lang%', 'en'); // replace placeholder in app.html
}
});
return response;
};Key Points
handleis the main hook — runs on every request, use for auth and middlewareevent.localspasses data from hooks → load functions → actionshandleFetchintercepts SSR fetch calls (add auth headers, rewrite URLs)handleErrorcatches unhandled errors for loggingsequence()composes multiple handle functions in order- Hooks are global — they affect every route in the app