## docs/kit/10-getting-started/10-introduction.md # SvelteKit Introduction ## What is SvelteKit? SvelteKit is a framework for building web applications using Svelte. Similar to Next.js (React) or Nuxt (Vue). ## What is Svelte? Svelte is a UI component framework that compiles components to optimized JavaScript and CSS. ## SvelteKit vs Svelte Svelte handles UI components. SvelteKit provides a complete application framework with: - Routing - Build optimizations - Offline support - Page preloading - Configurable rendering (SSR, CSR, prerendering) - Image optimization - HMR development experience via Vite ## Getting Started For beginners, check out the [interactive tutorial](/tutorial/kit) or get help in [Discord](/chat). ## docs/kit/10-getting-started/20-creating-a-project.md # Creating a SvelteKit Project ```bash npx sv create my-app cd my-app npm install npm run dev ``` This scaffolds a new project with optional TypeScript setup. Server runs on [localhost:5173](http://localhost:5173). ## Core Concepts - Pages are Svelte components - Pages are created in `src/routes` directory - Pages are server-rendered first, then hydrated client-side ## Editor Setup - Recommended: VS Code with [Svelte extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) - [Other editor support](https://sveltesociety.dev/resources#editor-support) ## docs/kit/10-getting-started/25-project-types.md # Project Types in SvelteKit SvelteKit offers configurable rendering to build various application types. Rendering settings can be mixed to optimize different parts of your application. ## Default Rendering - First page: Server-side rendering (SSR) - Subsequent pages: Client-side rendering (CSR) - Benefits: Better SEO, perceived performance, and smooth navigation ## Static Site Generation (SSG) ```js // Use adapter-static // In svelte.config.js import adapter from '@sveltejs/adapter-static'; export default { kit: { adapter: adapter() } }; // Prerender specific pages with // +page.js or +page.server.js export const prerender = true; ``` ## Single-Page App (SPA) ```js // In src/routes/+layout.js export const ssr = false; ``` ## Multi-Page App ```html About ``` ## Deployment Options - **Separate Backend**: Deploy SvelteKit frontend separately using `adapter-node` or serverless adapters - **Serverless**: Use `adapter-auto` (default), `adapter-vercel`, `adapter-netlify`, or `adapter-cloudflare` - **Own Server/Container**: Use `adapter-node` - **Library**: Use `@sveltejs/package` add-on - **Offline/PWA**: Leverage [service workers](service-workers) - **Mobile Apps**: Use Tauri or Capacitor with a SvelteKit SPA - **Desktop Apps**: Use Tauri, Wails, or Electron with a SvelteKit SPA - **Browser Extensions**: Use `adapter-static` or community adapters - **Embedded Devices**: Consider `bundleStrategy: 'single'` to reduce concurrent requests For mobile, desktop, and embedded applications, consider: ```js // svelte.config.js export default { kit: { output: { bundleStrategy: 'single' // Reduces concurrent connections } } }; ``` ## docs/kit/10-getting-started/30-project-structure.md # Project Structure in SvelteKit A typical SvelteKit project structure: ```bash my-project/ ├ src/ │ ├ lib/ │ │ ├ server/ # Server-only code │ │ └ [lib files] # Shared components/utilities │ ├ params/ # Param matchers │ ├ routes/ # Application routes │ ├ app.html # Page template │ ├ error.html # Error page │ ├ hooks.client.js │ ├ hooks.server.js │ └ service-worker.js ├ static/ # Static assets ├ tests/ # Tests ├ package.json ├ svelte.config.js ├ tsconfig.json └ vite.config.js ``` ## Key Files ### src/app.html Template with placeholders: - `%sveltekit.head%` - Links, scripts, and `` content - `%sveltekit.body%` - Rendered page markup (place inside a container element) - `%sveltekit.assets%` - Path to assets - `%sveltekit.nonce%` - CSP nonce - `%sveltekit.env.[NAME]%` - Environment variables (must start with `PUBLIC_`) ### src/error.html Fallback error page with placeholders: - `%sveltekit.status%` - HTTP status - `%sveltekit.error.message%` - Error message ### src/lib Library code importable via `$lib` alias. Server-only code goes in `src/lib/server` and is importable via `$lib/server`. ### src/routes Contains application routes and their components. ### static Static assets served as-is (favicon, robots.txt, etc.) ### Configuration Files - **package.json**: Must include `@sveltejs/kit`, `svelte`, and `vite` as `devDependencies` - **svelte.config.js**: Svelte and SvelteKit configuration - **vite.config.js**: Vite configuration with `@sveltejs/kit/vite` plugin - **tsconfig.json**: TypeScript configuration ### Generated Files The `.svelte-kit` directory contains generated files that can be safely deleted (they'll be regenerated). ## docs/kit/10-getting-started/40-web-standards.md # Svelte Web Standards ## Fetch APIs SvelteKit uses standard `fetch` for network requests in hooks, server routes, and browser. > Special `fetch` version in `load` functions, server hooks, and API routes allows direct endpoint invocation during SSR without HTTP calls, preserving credentials. ### Request ```js // Access in hooks and server routes export function GET({ request }) { const data = await request.json(); // or request.formData() } ``` ### Response ```js // Return from server routes import { json } from '@sveltejs/kit'; export function GET({ request }) { return json({ data: 'value' }); } ``` ### Headers ```js /// file: src/routes/what-is-my-user-agent/+server.js import { json } from '@sveltejs/kit'; /** @type {import('./$types').RequestHandler} */ export function GET({ request }) { // log all headers console.log(...request.headers); // create a JSON Response using a header we received return json({ // retrieve a specific header userAgent: request.headers.get('user-agent') }, { // set a header on the response headers: { 'x-custom-header': 'potato' } }); } ``` ## FormData ```js /// file: src/routes/hello/+server.js import { json } from '@sveltejs/kit'; /** @type {import('./$types').RequestHandler} */ export async function POST(event) { const body = await event.request.formData(); // log all fields console.log([...body]); return json({ // get a specific field's value name: body.get('name') ?? 'world' }); } ``` ## Stream APIs Use `ReadableStream`, `WritableStream`, and `TransformStream` for large responses or chunked data. ## URL APIs Access URL properties via `event.url` in hooks/server routes, `page.url` in pages, and `from`/`to` in navigation events. ### URLSearchParams ```js const foo = url.searchParams.get('foo'); ``` ## Web Crypto ```js const uuid = crypto.randomUUID(); ``` ## docs/kit/20-core-concepts/10-routing.md # SvelteKit Routing ## +page ### +page.svelte Defines a page component rendered on server (SSR) and browser (CSR). ```svelte

Hello and welcome to my site!

About my site ``` Receive data from load functions: ```svelte

{data.title}

{@html data.content}
``` ### +page.js Load data for pages: ```js import { error } from '@sveltejs/kit'; /** @type {import('./$types').PageLoad} */ export function load({ params }) { if (params.slug === 'hello-world') { return { title: 'Hello world!', content: 'Welcome to our blog. Lorem ipsum dolor sit amet...' }; } error(404, 'Not found'); } ``` Configure page behavior with exports: - `export const prerender = true|false|'auto'` - `export const ssr = true|false` - `export const csr = true|false` ### +page.server.js Server-only load functions: ```js import { error } from '@sveltejs/kit'; /** @type {import('./$types').PageServerLoad} */ export async function load({ params }) { const post = await getPostFromDatabase(params.slug); if (post) { return post; } error(404, 'Not found'); } ``` Also supports form actions. ## +error Custom error pages: ```svelte

{page.status}: {page.error.message}

``` SvelteKit walks up the tree to find the closest error boundary. ## +layout ### +layout.svelte Shared UI elements across multiple pages: ```svelte {@render children()} ``` Layouts can be nested: ```svelte

Settings

{@render children()} ``` ### +layout.js Load data for layouts: ```js /** @type {import('./$types').LayoutLoad} */ export function load() { return { sections: [ { slug: 'profile', title: 'Profile' }, { slug: 'notifications', title: 'Notifications' } ] }; } ``` ### +layout.server.js Server-only layout data loading. ## +server API routes with HTTP verb handlers: ```js import { error } from '@sveltejs/kit'; /** @type {import('./$types').RequestHandler} */ export function GET({ url }) { const min = Number(url.searchParams.get('min') ?? '0'); const max = Number(url.searchParams.get('max') ?? '1'); const d = max - min; if (isNaN(d) || d < 0) { error(400, 'min and max must be numbers, and min must be less than max'); } const random = min + Math.random() * d; return new Response(String(random)); } ``` Handling POST requests: ```js import { json } from '@sveltejs/kit'; /** @type {import('./$types').RequestHandler} */ export async function POST({ request }) { const { a, b } = await request.json(); return json(a + b); } ``` Fallback handler for unhandled methods: ```js /** @type {import('./$types').RequestHandler} */ export async function fallback({ request }) { return text(`I caught your ${request.method} request!`); } ``` Content negotiation: SvelteKit determines whether to serve a page or API response based on the `accept` header. ## $types TypeScript definitions for route files: - `PageProps`/`LayoutProps` - For component props - `PageLoad`/`PageServerLoad`/`LayoutLoad`/`LayoutServerLoad` - For load functions - `RequestHandler` - For server endpoints ## docs/kit/20-core-concepts/20-load.md # Loading Data in SvelteKit ## Page Data Load data for pages using `+page.js` or `+page.server.js`: ```js // src/routes/blog/[slug]/+page.js export function load({ params }) { return { post: { title: `Title for ${params.slug} goes here`, content: `Content for ${params.slug} goes here` } }; } ``` ```svelte

{data.post.title}

{@html data.post.content}
``` ## Layout Data Load data for layouts using `+layout.js` or `+layout.server.js`: ```js // src/routes/blog/[slug]/+layout.server.js export async function load() { return { posts: await db.getPostSummaries() }; } ``` ```svelte
{@render children()}
``` Child components can access parent layout data: ```svelte

{data.post.title}

{@html data.post.content}
{#if next}

Next post: {next.title}

{/if} ``` ## Universal vs Server Load Functions **Server load functions** (`+page.server.js`, `+layout.server.js`): - Always run on the server - Can access database, filesystem, private env vars - Must return serializable data - Have access to `cookies`, `locals`, etc. **Universal load functions** (`+page.js`, `+layout.js`): - Run on server during SSR, then in browser - Useful for fetching from external APIs - Can return non-serializable data (like component constructors) - Receive data from server load functions via the `data` property ## Making Fetch Requests Use the provided `fetch` function for enhanced features: ```js // src/routes/items/[id]/+page.js export async function load({ fetch, params }) { const res = await fetch(`/api/items/${params.id}`); const item = await res.json(); return { item }; } ``` ## Headers and Cookies Set response headers: ```js export async function load({ fetch, setHeaders }) { const response = await fetch(url); setHeaders({ age: response.headers.get('age'), 'cache-control': response.headers.get('cache-control') }); return response.json(); } ``` Access cookies in server load functions: ```js export async function load({ cookies }) { const sessionid = cookies.get('sessionid'); return { user: await db.getUser(sessionid) }; } ``` ## Using Parent Data Access data from parent load functions: ```js export async function load({ parent }) { const { a } = await parent(); return { b: a + 1 }; } ``` ## Errors and Redirects Throw errors: ```js import { error } from '@sveltejs/kit'; export function load({ locals }) { if (!locals.user) { error(401, 'not logged in'); } } ``` Redirect users: ```js import { redirect } from '@sveltejs/kit'; export function load({ locals }) { if (!locals.user) { redirect(307, '/login'); } } ``` ## Streaming with Promises Server load functions can stream promises as they resolve: ```js export async function load({ params }) { return { comments: loadComments(params.slug), post: await loadPost(params.slug) }; } ``` ```svelte

{data.post.title}

{@html data.post.content}
{#await data.comments} Loading comments... {:then comments} {#each comments as comment}

{comment.content}

{/each} {:catch error}

error loading comments: {error.message}

{/await} ``` ## Rerunning Load Functions Load functions rerun when: - Referenced params or URL properties change - A parent load function reran and `await parent()` was called - A dependency was invalidated with `invalidate(url)` or `invalidateAll()` Manually invalidate load functions: ```js // In load function export async function load({ fetch, depends }) { depends('app:random'); // ... } // In component import { invalidate } from '$app/navigation'; function rerunLoadFunction() { invalidate('app:random'); } ``` ## Dependency Tracking Exclude from dependency tracking with `untrack`: ```js export async function load({ untrack, url }) { if (untrack(() => url.pathname === '/')) { return { message: 'Welcome!' }; } } ``` ## docs/kit/20-core-concepts/30-form-actions.md # Svelte Form Actions ## Default Actions Define a default action in `+page.server.js`: ```js /// file: src/routes/login/+page.server.js /** @satisfies {import('./$types').Actions} */ export const actions = { default: async (event) => { // TODO log the user in } }; ``` Use it with a simple form: ```svelte
``` From other pages, specify the action path: ```html
``` ## Named Actions Multiple actions in one page: ```js /// file: src/routes/login/+page.server.js /** @satisfies {import('./$types').Actions} */ export const actions = { login: async (event) => { // TODO log the user in }, register: async (event) => { // TODO register the user } }; ``` Invoke with query parameter: ```svelte
``` Use `formaction` for multiple actions in one form: ```svelte
``` > Note: Can't mix default and named actions ## Action Implementation ```js import * as db from '$lib/server/db'; /** @satisfies {import('./$types').Actions} */ export const actions = { login: async ({ cookies, request }) => { const data = await request.formData(); const email = data.get('email'); const password = data.get('password'); const user = await db.getUser(email); cookies.set('sessionid', await db.createSession(user), { path: '/' }); return { success: true }; } }; ``` Access returned data in component: ```svelte {#if form?.success}

Successfully logged in! Welcome back, {data.user.name}

{/if} ``` ### Validation Errors Return errors with the `fail` function: ```js import { fail } from '@sveltejs/kit'; /** @satisfies {import('./$types').Actions} */ export const actions = { login: async ({ cookies, request }) => { const data = await request.formData(); const email = data.get('email'); const password = data.get('password'); if (!email) { return fail(400, { email, missing: true }); } const user = await db.getUser(email); if (!user || user.password !== db.hash(password)) { return fail(400, { email, incorrect: true }); } // Success case } }; ``` Handle errors in the component: ```svelte
{#if form?.missing}

The email field is required

{/if} {#if form?.incorrect}

Invalid credentials!

{/if}
``` ### Redirects ```js import { fail, redirect } from '@sveltejs/kit'; /** @satisfies {import('./$types').Actions} */ export const actions = { login: async ({ cookies, request, url }) => { // validation logic... if (url.searchParams.has('redirectTo')) { redirect(303, url.searchParams.get('redirectTo')); } return { success: true }; } }; ``` ## Loading Data After an action runs, the page's `load` functions run. If you modify cookies in an action, update `event.locals` too: ```js /// file: src/routes/account/+page.server.js /** @satisfies {import('./$types').Actions} */ export const actions = { logout: async (event) => { event.cookies.delete('sessionid', { path: '/' }); event.locals.user = null; } }; ``` ## Progressive Enhancement ### use:enhance Basic enhancement: ```svelte
``` Default behavior: - Updates `form` property and `page.form` (only for same-page actions) - Resets the form - Invalidates all data on success - Handles redirects and errors - Resets focus ### Customizing use:enhance ```svelte
{ // Pre-submission logic return async ({ result, update }) => { // Post-submission logic }; }} > ``` Custom handling with `applyAction`: ```svelte { return async ({ result }) => { if (result.type === 'redirect') { goto(result.location); } else { await applyAction(result); } }; }} > ``` ### Custom Event Listener ```svelte
``` To target `+page.server.js` actions with fetch: ```js const response = await fetch(this.action, { method: 'POST', body: data, headers: { 'x-sveltekit-action': 'true' } }); ``` ## GET Forms For forms that don't need to POST data: ```html
``` These navigate like `` elements and support the same data attributes for controlling router behavior. ## docs/kit/20-core-concepts/40-page-options.md # Svelte 5 Page Options ## Core Concepts ### Rendering Modes SvelteKit supports three rendering strategies: - **Server-Side Rendering (SSR)**: Default, renders on server first - **Client-Side Rendering (CSR)**: Hydrates server-rendered HTML - **Prerendering**: Generates static HTML at build time Options can be set in `+page.js`, `+page.server.js`, `+layout.js`, or `+layout.server.js`. Child pages override parent layouts. ## Page Options ### prerender Generate static HTML at build time: ```js /// file: +page.js/+page.server.js/+server.js export const prerender = true; // Enable for this route export const prerender = false; // Disable for this route export const prerender = 'auto'; // Prerender but keep in SSR manifest ``` **When to use prerendering**: - Content must be the same for all users - No need for `url.searchParams` during prerendering - Pages with [actions](form-actions) cannot be prerendered **Route conflicts**: Use file extensions for server routes to avoid conflicts: ``` src/routes/foo.json/+server.js // Creates foo.json src/routes/foo/bar.json/+server.js // Creates foo/bar.json ``` ### entries For dynamic routes that need prerendering: ```js /// file: src/routes/blog/[slug]/+page.server.js /** @type {import('./$types').EntryGenerator} */ export function entries() { return [ { slug: 'hello-world' }, { slug: 'another-blog-post' } ]; } export const prerender = true; ``` ### ssr Disable server-side rendering: ```js /// file: +page.js export const ssr = false; // Creates empty shell page, renders only on client ``` ### csr Disable client-side rendering: ```js /// file: +page.js export const csr = false; // No JavaScript sent to client, links cause full page navigation ``` Enable CSR only during development: ```js /// file: +page.js import { dev } from '$app/environment'; export const csr = dev; ``` ### trailingSlash Control URL trailing slashes: ```js /// file: src/routes/+layout.js export const trailingSlash = 'always'; // '/about/' format // Options: 'never' (default), 'always', 'ignore' ``` ### config Platform-specific configuration for adapters: ```js /// file: src/routes/+page.js /** @type {import('some-adapter').Config} */ export const config = { runtime: 'edge' }; ``` Config objects merge at the top level but not deeper levels. ## Best Practices - Use prerendering for static content - Use SSR for dynamic, SEO-important pages - Use CSR-only (SPA mode) for admin sections - Avoid ignoring trailing slashes (harmful for SEO) - Keep browser-only code in component files, not in page option files ## docs/kit/20-core-concepts/50-state-management.md # Svelte 5 State Management ## Server State Guidelines ### Avoid Shared State on Server Servers are stateless and shared by multiple users. Never store user data in shared variables: ```js // NEVER DO THIS! let user; // Shared by all users export function load() { return { user }; } export const actions = { default: async ({ request }) => { const data = await request.formData(); user = { // BAD: exposes one user's data to others name: data.get('name'), secret: data.get('secret') }; } } ``` Instead, authenticate users with cookies and store data in databases. ### No Side-Effects in Load Load functions should be pure: ```js // NEVER DO THIS! import { user } from '$lib/user'; export async function load({ fetch }) { const response = await fetch('/api/user'); user.set(await response.json()); // BAD: shared state } ``` Instead, return the data: ```js export async function load({ fetch }) { const response = await fetch('/api/user'); return { user: await response.json() }; } ``` ## Using Context for State Use Svelte's context API for component tree state: ```svelte ``` ```svelte

Welcome {user().name}

``` > Pass functions to `setContext` to maintain reactivity across boundaries. ## Component State Preservation SvelteKit reuses components during navigation. Make values reactive to handle updates: ```svelte ``` Correct approach: ```svelte ``` To force component remounting on navigation: ```svelte {#key page.url.pathname} {/key} ``` ## State Storage Options ### URL State For state that should survive reloads, use URL search parameters (`?sort=price&order=ascending`). Access via: - Load functions: `url` parameter - Components: `page.url.searchParams` ### Ephemeral State For UI state that should persist during session navigation but can be lost on refresh, use [snapshots](snapshots). ## docs/kit/25-build-and-deploy/10-building-your-app.md # Building your app ## Build Process SvelteKit builds in two stages when running `vite build`: 1. Vite creates optimized production builds of server code, browser code, and service worker 2. An adapter tunes the build for your target environment ## During the build Skip code execution during build phase: ```js import { building } from '$app/environment'; import { setupMyDatabase } from '$lib/server/database'; if (!building) { setupMyDatabase(); } export function load() { // ... } ``` ## Preview Preview production build locally with `vite preview` (via `npm run preview`). Note that this runs in Node and doesn't perfectly reproduce deployment environment (adapter-specific features like the `platform` object aren't available). ## docs/kit/25-build-and-deploy/20-adapters.md # Adapters Adapters convert your SvelteKit app for deployment to specific platforms. ## Official Adapters - `@sveltejs/adapter-cloudflare` - For Cloudflare Workers and Pages - `@sveltejs/adapter-netlify` - For Netlify - `@sveltejs/adapter-node` - For Node servers - `@sveltejs/adapter-static` - For static site generation (SSG) - `@sveltejs/adapter-vercel` - For Vercel [Community adapters](https://sveltesociety.dev/packages?category=sveltekit-adapters) are available for other platforms. ## Configuration Specify your adapter in `svelte.config.js`: ```js /// file: svelte.config.js import adapter from 'svelte-adapter-foo'; /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { adapter: adapter({ // adapter options go here }) } }; export default config; ``` ## Platform-specific Context Adapters can provide platform-specific information via the `platform` property in the `RequestEvent` object used in hooks and server routes. Refer to each adapter's documentation for details. ## docs/kit/25-build-and-deploy/55-single-page-apps.md # Single-page apps in SvelteKit ## Basic Setup Convert any SvelteKit app to a SPA by disabling SSR in the root layout: ```js /// file: src/routes/+layout.js export const ssr = false; ``` > **Note**: Not recommended for most cases due to SEO, performance, and accessibility issues. ## Using adapter-static For apps without server-side logic, use `adapter-static` with a fallback page: ```js /// file: svelte.config.js import adapter from '@sveltejs/adapter-static'; export default { kit: { adapter: adapter({ fallback: '200.html' // platform-specific }) } }; ``` The fallback page loads your app and navigates to the correct route. The filename varies by hosting platform. ## Apache Configuration For Apache, add a `static/.htaccess` file: ``` RewriteEngine On RewriteBase / RewriteRule ^200\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /200.html [L] ``` ## Selective Prerendering Enable prerendering for specific pages: ```js /// file: src/routes/my-prerendered-page/+page.js export const prerender = true; export const ssr = true; ``` ## docs/kit/30-advanced/10-advanced-routing.md # Advanced Routing in SvelteKit ## Rest Parameters Use rest syntax for unknown number of route segments: ```bash /[org]/[repo]/tree/[branch]/[...file] ``` For `/sveltejs/kit/tree/main/documentation/docs/04-advanced-routing.md`: ```js { org: 'sveltejs', repo: 'kit', branch: 'main', file: 'documentation/docs/04-advanced-routing.md' } ``` > Note: `src/routes/a/[...rest]/z/+page.svelte` matches `/a/z`, `/a/b/z`, etc. Always validate rest parameters. ### Custom 404 Pages For custom 404s with nested routes, create a catch-all route: ```js /// file: src/routes/marx-brothers/[...path]/+page.js import { error } from '@sveltejs/kit'; /** @type {import('./$types').PageLoad} */ export function load(event) { error(404, 'Not Found'); } ``` ## Optional Parameters Make parameters optional with double brackets: `[[lang]]/home` This matches both `/home` and `/en/home`. > Note: Optional parameters can't follow rest parameters. ## Matching Ensure parameters are well-formed with matchers: ```js /// file: src/params/fruit.js /** * @param {string} param * @return {param is ('apple' | 'orange')} * @satisfies {import('@sveltejs/kit').ParamMatcher} */ export function match(param) { return param === 'apple' || param === 'orange'; } ``` Use in routes: ``` src/routes/fruits/[page=fruit] ``` ## Sorting Routes are sorted by: 1. Specificity (more specific routes have higher priority) 2. Matchers (routes with matchers have higher priority) 3. Optional/rest parameters (lowest priority) 4. Alphabetically (for ties) ## Encoding Use hexadecimal escape sequences for special characters: - `[x+5c]` for `\` - `[x+2f]` for `/` - `[x+23]` for `#` - etc. Example: For `/smileys/:-)` create `src/routes/smileys/[x+3a]-[x+29]/+page.svelte` Unicode escapes also work: `src/routes/[u+d83e][u+dd2a]/+page.svelte` equals `src/routes/🤪/+page.svelte` ## Advanced Layouts ### (group) Group routes without affecting URL paths: ```tree src/routes/ │ (app)/ │ ├ dashboard/ │ ├ item/ │ └ +layout.svelte │ (marketing)/ │ ├ about/ │ ├ testimonials/ │ └ +layout.svelte ├ admin/ └ +layout.svelte ``` ### Breaking Out of Layouts Use `@` to break out of layout hierarchy: - `+page@[id].svelte` - inherits from segment's layout - `+page@item.svelte` - inherits from parent segment's layout - `+page@(app).svelte` - inherits from group layout - `+page@.svelte` - inherits from root layout Example: ```tree src/routes/ ├ (app)/ │ ├ item/ │ │ ├ [id]/ │ │ │ ├ embed/ │ │ │ │ └ +page@(app).svelte │ │ │ └ +layout.svelte │ │ └ +layout.svelte │ └ +layout.svelte └ +layout.svelte ``` Layouts can also break out with `+layout@.svelte`. Consider composition as an alternative to complex layout grouping: ```svelte {@render children()} ``` ## docs/kit/30-advanced/20-hooks.md # SvelteKit Hooks Hooks are app-wide functions that SvelteKit calls in response to specific events. ## Files - `src/hooks.server.js` - server hooks - `src/hooks.client.js` - client hooks - `src/hooks.js` - universal hooks (both client and server) ## Server Hooks ### handle Runs on every request to determine the response. ```js /** @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; } ``` `resolve` accepts optional parameters: ```js /** @type {import('@sveltejs/kit').Handle} */ export async function handle({ event, resolve }) { const response = await resolve(event, { transformPageChunk: ({ html }) => html.replace('old', 'new'), filterSerializedResponseHeaders: (name) => name.startsWith('x-'), preload: ({ type, path }) => type === 'js' || path.includes('/important/') }); return response; } ``` ### locals Add custom data to the request: ```js /** @type {import('@sveltejs/kit').Handle} */ export async function handle({ event, resolve }) { event.locals.user = await getUserInformation(event.cookies.get('sessionid')); const response = await resolve(event); response.headers.set('x-custom-header', 'potato'); return response; } ``` ### handleFetch Modify or replace fetch requests in server-side `load` or `action` functions: ```js /** @type {import('@sveltejs/kit').HandleFetch} */ export async function handleFetch({ request, fetch }) { if (request.url.startsWith('https://api.yourapp.com/')) { request = new Request( request.url.replace('https://api.yourapp.com/', 'http://localhost:9999/'), request ); } return fetch(request); } ``` ## Shared Hooks (Server and Client) ### handleError Handle unexpected errors during loading or rendering: ```js /** @type {import('@sveltejs/kit').HandleServerError} */ export async function handleError({ error, event, status, message }) { const errorId = crypto.randomUUID(); // Log to service like Sentry Sentry.captureException(error, { extra: { event, errorId, status } }); return { message: 'Whoops!', errorId }; } ``` ### init Runs once when server is created or app starts in browser: ```js /** @type {import('@sveltejs/kit').ServerInit} */ export async function init() { await db.connect(); } ``` ## Universal Hooks ### reroute Change how URLs translate to routes: ```js /** @type {import('@sveltejs/kit').Reroute} */ export function reroute({ url }) { const translated = { '/en/about': '/en/about', '/de/ueber-uns': '/de/about', '/fr/a-propos': '/fr/about', }; if (url.pathname in translated) { return translated[url.pathname]; } } ``` Can be async since v2.18: ```js /** @type {import('@sveltejs/kit').Reroute} */ export async function reroute({ url, fetch }) { if (url.pathname === '/api/reroute') return; const api = new URL('/api/reroute', url); api.searchParams.set('pathname', url.pathname); const result = await fetch(api).then(r => r.json()); return result.pathname; } ``` ### transport Pass custom types across server/client boundary: ```js /** @type {import('@sveltejs/kit').Transport} */ export const transport = { Vector: { encode: (value) => value instanceof Vector && [value.x, value.y], decode: ([x, y]) => new Vector(x, y) } }; ``` ## docs/kit/30-advanced/25-errors.md # Svelte Errors ## Error Objects SvelteKit handles two types of errors: - Expected errors (created with `error` helper) - Unexpected errors (other exceptions) Both are represented as `{ message: string }` objects by default, but can be extended. ## Expected Errors ```js import { error } from '@sveltejs/kit'; export async function load({ params }) { const post = await db.getPost(params.slug); if (!post) { error(404, { message: 'Not found' }); } return { post }; } ``` Access errors in components: ```svelte

{page.error.message}

``` Shorthand for simple errors: ```js error(404, 'Not found'); // Same as error(404, { message: 'Not found' }) ``` Add custom properties: ```js error(404, { message: 'Not found', code: 'NOT_FOUND' }); ``` ## Unexpected Errors Unexpected errors are any other exceptions. For security, their details aren't exposed to users. Default error shape: `{ "message": "Internal Error" }` Use `handleError` hook for custom error handling (reporting, custom responses). ## Error Responses Error handling depends on context: - In `handle` or `+server.js`: Returns fallback error page or JSON - In `load` functions: Renders nearest `+error.svelte` component Custom fallback error page (`src/error.html`): ```html %sveltekit.error.message%

My custom error page

Status: %sveltekit.status%

Message: %sveltekit.error.message%

``` ## Type Safety Customize error shape with TypeScript: ```ts declare global { namespace App { interface Error { code: string; id: string; } } } export {}; ``` ## docs/kit/30-advanced/30-link-options.md # Link Options in SvelteKit SvelteKit uses standard `
` elements for navigation between routes. When clicking a link within your app, SvelteKit imports the code and calls necessary `load` functions to fetch data. ## data-sveltekit-preload-data Controls when data preloading begins: - `"hover"` - starts on mouse hover or mobile `touchstart` - `"tap"` - starts on `touchstart` or `mousedown` Default setup in `app.html`: ```html
%sveltekit.body%
``` For time-sensitive data: ```html
Get current stonk values ``` Preloading is skipped if `navigator.connection.saveData` is `true`. ## data-sveltekit-preload-code Controls when code preloading begins: - `"eager"` - preloads immediately - `"viewport"` - preloads when link enters viewport - `"hover"` - preloads on hover - `"tap"` - preloads on tap/click `viewport` and `eager` only apply to links present in DOM immediately after navigation. ## data-sveltekit-reload Forces full-page navigation: ```html Path ``` Links with `rel="external"` behave the same and are ignored during prerendering. ## data-sveltekit-replacestate Replaces current history entry instead of creating a new one: ```html Path ``` ## data-sveltekit-keepfocus Maintains focus on the current element after navigation: ```html
``` Avoid using on links for accessibility reasons. Only use on elements that exist after navigation. ## data-sveltekit-noscroll Prevents scrolling to top after navigation: ```html Path ``` ## Disabling Options Use `"false"` to disable options within a parent element: ```html
a
d
``` Conditional application: ```svelte
``` ## docs/kit/30-advanced/40-service-workers.md # Service Workers in SvelteKit Service workers act as proxy servers for network requests, enabling offline support and faster navigation through precaching. ## Basic Setup SvelteKit automatically registers `src/service-worker.js` (or `src/service-worker/index.js`). ```js // Manual registration (if you disable automatic registration) if ('serviceWorker' in navigator) { addEventListener('load', function () { navigator.serviceWorker.register('./path/to/service-worker.js'); }); } ``` ## Inside the Service Worker Access the `$service-worker` module for paths to assets, build files, and prerendered pages. ```js /// import { build, files, version } from '$service-worker'; // Create a unique cache name for this deployment const CACHE = `cache-${version}`; const ASSETS = [ ...build, // the app itself ...files // everything in `static` ]; self.addEventListener('install', (event) => { // Create a new cache and add all files to it async function addFilesToCache() { const cache = await caches.open(CACHE); await cache.addAll(ASSETS); } event.waitUntil(addFilesToCache()); }); self.addEventListener('activate', (event) => { // Remove previous cached data from disk async function deleteOldCaches() { for (const key of await caches.keys()) { if (key !== CACHE) await caches.delete(key); } } event.waitUntil(deleteOldCaches()); }); self.addEventListener('fetch', (event) => { // ignore POST requests etc if (event.request.method !== 'GET') return; async function respond() { const url = new URL(event.request.url); const cache = await caches.open(CACHE); // `build`/`files` can always be served from the cache if (ASSETS.includes(url.pathname)) { const response = await cache.match(url.pathname); if (response) { return response; } } // for everything else, try the network first, but // fall back to the cache if we're offline try { const response = await fetch(event.request); // if we're offline, fetch can return a value that is not a Response // instead of throwing - and we can't pass this non-Response to respondWith if (!(response instanceof Response)) { throw new Error('invalid response from fetch'); } if (response.status === 200) { cache.put(event.request, response.clone()); } return response; } catch (err) { const response = await cache.match(event.request); if (response) { return response; } // if there's no cache, then just error out throw err; } } event.respondWith(respond()); }); ``` > Be careful with caching - stale data may be worse than unavailable data, and browsers will empty caches if they get too full. ## Development Mode Service workers are bundled for production but not during development. Only browsers supporting modules in service workers will work in dev mode. ```js import { dev } from '$app/environment'; navigator.serviceWorker.register('/service-worker.js', { type: dev ? 'module' : 'classic' }); ``` > `build` and `prerendered` are empty arrays during development ## Type Safety ```js /// /// /// /// const sw = /** @type {ServiceWorkerGlobalScope} */ (/** @type {unknown} */ (self)); ``` ## Alternatives - [Vite PWA plugin](https://vite-pwa-org.netlify.app/frameworks/sveltekit.html) for Workbox integration - [MDN Service Worker docs](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers) ## docs/kit/30-advanced/50-server-only-modules.md # Server-only modules ## Private environment variables [`$env/static/private`]($env-static-private) and [`$env/dynamic/private`]($env-dynamic-private) can only be imported into server-side modules like `hooks.server.js` or `+page.server.js`. ## Server-only utilities [`$app/server`]($app-server) module with its [`read`]($app-server#read) function can only be imported by server code. ## Your modules Make your modules server-only by: - Adding `.server` to filename: `secrets.server.js` - Placing in `$lib/server`: `$lib/server/secrets.js` ## How it works SvelteKit prevents importing server-only code in public-facing components: ```js /// file: $lib/server/secrets.js export const atlantisCoordinates = [/* redacted */]; ``` ```js /// file: src/routes/utils.js export { atlantisCoordinates } from '$lib/server/secrets.js'; export const add = (a, b) => a + b; ``` ```html /// file: src/routes/+page.svelte ``` This produces an error: ``` Cannot import $lib/server/secrets.js into public-facing code: src/routes/+page.svelte src/routes/utils.js $lib/server/secrets.js ``` Works with dynamic imports too, though with multiple dynamic imports, illegal imports might not be detected on first load during development. > [!NOTE] Import detection is disabled during tests when `process.env.TEST === 'true'`. ## docs/kit/30-advanced/65-snapshots.md # Snapshots Preserve ephemeral DOM state (form inputs, scroll positions) between navigations. ```svelte