/ routing.md
routing.md
  1  At the heart of SvelteKit is a _filesystem-based router_. The routes of your app — i.e. the URL paths that users can access — are defined by the directories in your codebase:
  2  
  3  - `src/routes` is the root route
  4  - `src/routes/about` creates an `/about` route
  5  - `src/routes/blog/[slug]` creates a route with a _parameter_, `slug`, that can be used to load data dynamically when a user requests a page like `/blog/hello-world`
  6  
  7  > [!NOTE] You can change `src/routes` to a different directory by editing the [project config](configuration).
  8  
  9  Each route directory contains one or more _route files_, which can be identified by their `+` prefix.
 10  
 11  We'll introduce these files in a moment in more detail, but here are a few simple rules to help you remember how SvelteKit's routing works:
 12  
 13  - All files can run on the server
 14  - All files run on the client except `+server` files
 15  - `+layout` and `+error` files apply to subdirectories as well as the directory they live in
 16  
 17  ## +page
 18  
 19  ### +page.svelte
 20  
 21  A `+page.svelte` component defines a page of your app. By default, pages are rendered both on the server ([SSR](glossary#SSR)) for the initial request and in the browser ([CSR](glossary#CSR)) for subsequent navigation.
 22  
 23  ```svelte
 24  <!--- file: src/routes/+page.svelte --->
 25  <h1>Hello and welcome to my site!</h1>
 26  <a href="/about">About my site</a>
 27  ```
 28  
 29  ```svelte
 30  <!--- file: src/routes/about/+page.svelte --->
 31  <h1>About this site</h1>
 32  <p>TODO...</p>
 33  <a href="/">Home</a>
 34  ```
 35  
 36  > [!NOTE] SvelteKit uses `<a>` elements to navigate between routes, rather than a framework-specific `<Link>` component.
 37  
 38  Pages can receive data from `load` functions via the `data` prop.
 39  
 40  ```svelte
 41  <!--- file: src/routes/blog/[slug]/+page.svelte --->
 42  <script>
 43  	/** @type {import('./$types').PageProps} */
 44  	let { data } = $props();
 45  </script>
 46  
 47  <h1>{data.title}</h1><div>{@html data.content}</div>
 48  ```
 49  
 50  As of 2.24, pages also receive a `params` prop which is typed based on the route parameters. This is particularly useful alongside [remote functions](remote-functions):
 51  
 52  ```svelte
 53  <!--- file: src/routes/blog/[slug]/+page.svelte --->
 54  <script>
 55  	import { getPost } from '../blog.remote';
 56  
 57  	/** @type {import('./$types').PageProps} */
 58  	let { params } = $props();
 59  
 60  	const post = $derived(await getPost(params.slug));
 61  </script>
 62  
 63  <h1>{post.title}</h1><div>{@html post.content}</div>
 64  ```
 65  
 66  > [!LEGACY]
 67  > `PageProps` was added in 2.16.0. In earlier versions, you had to type the `data` property manually with `PageData` instead, see [$types](#$types).
 68  >
 69  > In Svelte 4, you'd use `export let data` instead.
 70  
 71  ### +page.js
 72  
 73  Often, a page will need to load some data before it can be rendered. For this, we add a `+page.js` module that exports a `load` function:
 74  
 75  ```js
 76  /// file: src/routes/blog/[slug]/+page.js
 77  import { error } from '@sveltejs/kit';
 78  
 79  /** @type {import('./$types').PageLoad} */
 80  export function load({ params }) {
 81  	if (params.slug === 'hello-world') {
 82  		return {
 83  			title: 'Hello world!',
 84  			content: 'Welcome to our blog. Lorem ipsum dolor sit amet...'
 85  		};
 86  	}
 87  
 88  	error(404, 'Not found');
 89  }
 90  ```
 91  
 92  This function runs alongside `+page.svelte`, which means it runs on the server during server-side rendering and in the browser during client-side navigation. See [`load`](load) for full details of the API.
 93  
 94  As well as `load`, `+page.js` can export values that configure the page's behaviour:
 95  
 96  - `export const prerender = true` or `false` or `'auto'`
 97  - `export const ssr = true` or `false`
 98  - `export const csr = true` or `false`
 99  
100  You can find more information about these in [page options](page-options).
101  
102  ### +page.server.js
103  
104  If your `load` function can only run on the server — for example, if it needs to fetch data from a database or you need to access private [environment variables]($env-static-private) like API keys — then you can rename `+page.js` to `+page.server.js` and change the `PageLoad` type to `PageServerLoad`.
105  
106  ```js
107  /// file: src/routes/blog/[slug]/+page.server.js
108  
109  // @filename: ambient.d.ts
110  declare global {
111  	const getPostFromDatabase: (slug: string) => {
112  		title: string;
113  		content: string;
114  	}
115  }
116  
117  export {};
118  
119  // @filename: index.js
120  // ---cut---
121  import { error } from '@sveltejs/kit';
122  
123  /** @type {import('./$types').PageServerLoad} */
124  export async function load({ params }) {
125  	const post = await getPostFromDatabase(params.slug);
126  
127  	if (post) {
128  		return post;
129  	}
130  
131  	error(404, 'Not found');
132  }
133  ```
134  
135  During client-side navigation, SvelteKit will load this data from the server, which means that the returned value must be serializable using [devalue](https://github.com/rich-harris/devalue). See [`load`](load) for full details of the API.
136  
137  Like `+page.js`, `+page.server.js` can export [page options](page-options) — `prerender`, `ssr` and `csr`.
138  
139  A `+page.server.js` file can also export _actions_. If `load` lets you read data from the server, `actions` let you write data _to_ the server using the `<form>` element. To learn how to use them, see the [form actions](form-actions) section.
140  
141  ## +error
142  
143  If an error occurs during `load`, SvelteKit will render a default error page. You can customise this error page on a per-route basis by adding an `+error.svelte` file:
144  
145  ```svelte
146  <!--- file: src/routes/blog/[slug]/+error.svelte --->
147  <script>
148  	import { page } from '$app/state';
149  </script>
150  
151  <h1>{page.status}: {page.error.message}</h1>
152  ```
153  
154  > [!LEGACY]
155  > `$app/state` was added in SvelteKit 2.12. If you're using an earlier version or are using Svelte 4, use `$app/stores` instead.
156  
157  SvelteKit will 'walk up the tree' looking for the closest error boundary — if the file above didn't exist it would try `src/routes/blog/+error.svelte` and then `src/routes/+error.svelte` before rendering the default error page. If _that_ fails (or if the error was thrown from the `load` function of the root `+layout`, which sits 'above' the root `+error`), SvelteKit will bail out and render a static fallback error page, which you can customise by creating a `src/error.html` file.
158  
159  If the error occurs inside a `load` function in `+layout(.server).js`, the closest error boundary in the tree is an `+error.svelte` file _above_ that layout (not next to it).
160  
161  If no route can be found (404), `src/routes/+error.svelte` (or the default error page, if that file does not exist) will be used.
162  
163  > [!NOTE] `+error.svelte` is _not_ used when an error occurs inside [`handle`](hooks#Server-hooks-handle) or a [+server.js](#server) request handler.
164  
165  You can read more about error handling [here](errors).
166  
167  ## +layout
168  
169  So far, we've treated pages as entirely standalone components — upon navigation, the existing `+page.svelte` component will be destroyed, and a new one will take its place.
170  
171  But in many apps, there are elements that should be visible on _every_ page, such as top-level navigation or a footer. Instead of repeating them in every `+page.svelte`, we can put them in _layouts_.
172  
173  ### +layout.svelte
174  
175  To create a layout that applies to every page, make a file called `src/routes/+layout.svelte`. The default layout (the one that SvelteKit uses if you don't bring your own) looks like this...
176  
177  ```svelte
178  <script>
179  	let { children } = $props();
180  </script>
181  
182  {@render children()}
183  ```
184  
185  ...but we can add whatever markup, styles and behaviour we want. The only requirement is that the component includes a `@render` tag for the page content. For example, let's add a nav bar:
186  
187  ```svelte
188  <!--- file: src/routes/+layout.svelte --->
189  <script>
190  	let { children } = $props();
191  </script>
192  
193  <nav>
194  	<a href="/">Home</a>
195  	<a href="/about">About</a>
196  	<a href="/settings">Settings</a>
197  </nav>
198  
199  {@render children()}
200  ```
201  
202  If we create pages for `/`, `/about` and `/settings`...
203  
204  ```html
205  /// file: src/routes/+page.svelte
206  <h1>Home</h1>
207  ```
208  
209  ```html
210  /// file: src/routes/about/+page.svelte
211  <h1>About</h1>
212  ```
213  
214  ```html
215  /// file: src/routes/settings/+page.svelte
216  <h1>Settings</h1>
217  ```
218  
219  ...the nav will always be visible, and clicking between the three pages will only result in the `<h1>` being replaced.
220  
221  Layouts can be _nested_. Suppose we don't just have a single `/settings` page, but instead have nested pages like `/settings/profile` and `/settings/notifications` with a shared submenu (for a real-life example, see [github.com/settings](https://github.com/settings)).
222  
223  We can create a layout that only applies to pages below `/settings` (while inheriting the root layout with the top-level nav):
224  
225  ```svelte
226  <!--- file: src/routes/settings/+layout.svelte --->
227  <script>
228  	/** @type {import('./$types').LayoutProps} */
229  	let { data, children } = $props();
230  </script>
231  
232  <h1>Settings</h1>
233  
234  <div class="submenu">
235  	{#each data.sections as section}
236  		<a href="/settings/{section.slug}">{section.title}</a>
237  	{/each}
238  </div>
239  
240  {@render children()}
241  ```
242  
243  > [!LEGACY]
244  > `LayoutProps` was added in 2.16.0. In earlier versions, you had to [type the properties manually instead](#$types).
245  
246  You can see how `data` is populated by looking at the `+layout.js` example in the next section just below.
247  
248  By default, each layout inherits the layout above it. Sometimes that isn't what you want - in this case, [advanced layouts](advanced-routing#Advanced-layouts) can help you.
249  
250  ### +layout.js
251  
252  Just like `+page.svelte` loading data from `+page.js`, your `+layout.svelte` component can get data from a [`load`](load) function in `+layout.js`.
253  
254  ```js
255  /// file: src/routes/settings/+layout.js
256  /** @type {import('./$types').LayoutLoad} */
257  export function load() {
258  	return {
259  		sections: [
260  			{ slug: 'profile', title: 'Profile' },
261  			{ slug: 'notifications', title: 'Notifications' }
262  		]
263  	};
264  }
265  ```
266  
267  If a `+layout.js` exports [page options](page-options) — `prerender`, `ssr` and `csr` — they will be used as defaults for child pages.
268  
269  Data returned from a layout's `load` function is also available to all its child pages:
270  
271  ```svelte
272  <!--- file: src/routes/settings/profile/+page.svelte --->
273  <script>
274  	/** @type {import('./$types').PageProps} */
275  	let { data } = $props();
276  
277  	console.log(data.sections); // [{ slug: 'profile', title: 'Profile' }, ...]
278  </script>
279  ```
280  
281  > [!NOTE] Often, layout data is unchanged when navigating between pages. SvelteKit will intelligently rerun [`load`](load) functions when necessary.
282  
283  ### +layout.server.js
284  
285  To run your layout's `load` function on the server, move it to `+layout.server.js`, and change the `LayoutLoad` type to `LayoutServerLoad`.
286  
287  Like `+layout.js`, `+layout.server.js` can export [page options](page-options) — `prerender`, `ssr` and `csr`.
288  
289  ## +server
290  
291  As well as pages, you can define routes with a `+server.js` file (sometimes referred to as an 'API route' or an 'endpoint'), which gives you full control over the response. Your `+server.js` file exports functions corresponding to HTTP verbs like `GET`, `POST`, `PATCH`, `PUT`, `DELETE`, `OPTIONS`, and `HEAD` that take a [`RequestEvent`](@sveltejs-kit#RequestEvent) argument and return a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object.
292  
293  For example we could create an `/api/random-number` route with a `GET` handler:
294  
295  ```js
296  /// file: src/routes/api/random-number/+server.js
297  import { error } from '@sveltejs/kit';
298  
299  /** @type {import('./$types').RequestHandler} */
300  export function GET({ url }) {
301  	const min = Number(url.searchParams.get('min') ?? '0');
302  	const max = Number(url.searchParams.get('max') ?? '1');
303  
304  	const d = max - min;
305  
306  	if (isNaN(d) || d < 0) {
307  		error(400, 'min and max must be numbers, and min must be less than max');
308  	}
309  
310  	const random = min + Math.random() * d;
311  
312  	return new Response(String(random));
313  }
314  ```
315  
316  The first argument to `Response` can be a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream), making it possible to stream large amounts of data or create server-sent events (unless deploying to platforms that buffer responses, like AWS Lambda).
317  
318  You can use the [`error`](@sveltejs-kit#error), [`redirect`](@sveltejs-kit#redirect) and [`json`](@sveltejs-kit#json) methods from `@sveltejs/kit` for convenience (but you don't have to).
319  
320  If an error is thrown (either `error(...)` or an unexpected error), the response will be a JSON representation of the error or a fallback error page — which can be customised via `src/error.html` — depending on the `Accept` header. The [`+error.svelte`](#error) component will _not_ be rendered in this case. You can read more about error handling [here](errors).
321  
322  > [!NOTE] When creating an `OPTIONS` handler, note that Vite will inject `Access-Control-Allow-Origin` and `Access-Control-Allow-Methods` headers — these will not be present in production unless you add them.
323  
324  > [!NOTE] `+layout` files have no effect on `+server.js` files. If you want to run some logic before each request, add it to the server [`handle`](hooks#Server-hooks-handle) hook.
325  
326  ### Receiving data
327  
328  By exporting `POST`/`PUT`/`PATCH`/`DELETE`/`OPTIONS`/`HEAD` handlers, `+server.js` files can be used to create a complete API:
329  
330  ```svelte
331  <!--- file: src/routes/add/+page.svelte --->
332  <script>
333  	let a = $state(0);
334  	let b = $state(0);
335  	let total = $state(0);
336  
337  	async function add() {
338  		const response = await fetch('/api/add', {
339  			method: 'POST',
340  			body: JSON.stringify({ a, b }),
341  			headers: {
342  				'content-type': 'application/json'
343  			}
344  		});
345  
346  		total = await response.json();
347  	}
348  </script>
349  
350  <input type="number" bind:value={a} /> +
351  <input type="number" bind:value={b} /> =
352  {total}
353  
354  <button onclick={add}>Calculate</button>
355  ```
356  
357  ```js
358  /// file: src/routes/api/add/+server.js
359  import { json } from '@sveltejs/kit';
360  
361  /** @type {import('./$types').RequestHandler} */
362  export async function POST({ request }) {
363  	const { a, b } = await request.json();
364  	return json(a + b);
365  }
366  ```
367  
368  > [!NOTE] In general, [form actions](form-actions) are a better way to submit data from the browser to the server.
369  
370  > [!NOTE] If a `GET` handler is exported, a `HEAD` request will return the `content-length` of the `GET` handler's response body.
371  
372  ### Fallback method handler
373  
374  Exporting the `fallback` handler will match any unhandled request methods, including methods like `MOVE` which have no dedicated export from `+server.js`.
375  
376  ```js
377  /// file: src/routes/api/add/+server.js
378  import { json, text } from '@sveltejs/kit';
379  
380  /** @type {import('./$types').RequestHandler} */
381  export async function POST({ request }) {
382  	const { a, b } = await request.json();
383  	return json(a + b);
384  }
385  
386  // This handler will respond to PUT, PATCH, DELETE, etc.
387  /** @type {import('./$types').RequestHandler} */
388  export async function fallback({ request }) {
389  	return text(`I caught your ${request.method} request!`);
390  }
391  ```
392  
393  > [!NOTE] For `HEAD` requests, the `GET` handler takes precedence over the `fallback` handler.
394  
395  ### Content negotiation
396  
397  `+server.js` files can be placed in the same directory as `+page` files, allowing the same route to be either a page or an API endpoint. To determine which, SvelteKit applies the following rules:
398  
399  - `PUT`/`PATCH`/`DELETE`/`OPTIONS` requests are always handled by `+server.js` since they do not apply to pages
400  - `GET`/`POST`/`HEAD` requests are treated as page requests if the `accept` header prioritises `text/html` (in other words, it's a browser page request), else they are handled by `+server.js`.
401  - Responses to `GET` requests will include a `Vary: Accept` header, so that proxies and browsers cache HTML and JSON responses separately.
402  
403  ## $types
404  
405  Throughout the examples above, we've been importing types from a `$types.d.ts` file. This is a file SvelteKit creates for you in a hidden directory if you're using TypeScript (or JavaScript with JSDoc type annotations) to give you type safety when working with your root files.
406  
407  For example, annotating `let { data } = $props()` with `PageProps` (or `LayoutProps`, for a `+layout.svelte` file) tells TypeScript that the type of `data` is whatever was returned from `load`:
408  
409  ```svelte
410  <!--- file: src/routes/blog/[slug]/+page.svelte --->
411  <script>
412  	/** @type {import('./$types').PageProps} */
413  	let { data } = $props();
414  </script>
415  ```
416  
417  > [!NOTE]
418  > The `PageProps` and `LayoutProps` types, added in 2.16.0, are a shortcut for typing the `data` prop as `PageData` or `LayoutData`, as well as other props, such as `form` for pages, or `children` for layouts. In earlier versions, you had to type these properties manually. For example, for a page:
419  >
420  > ```js
421  > /// file: +page.svelte
422  > /** @type {{ data: import('./$types').PageData, form: import('./$types').ActionData }} */
423  > let { data, form } = $props();
424  > ```
425  >
426  > Or, for a layout:
427  >
428  > ```js
429  > /// file: +layout.svelte
430  > /** @type {{ data: import('./$types').LayoutData, children: Snippet }} */
431  > let { data, children } = $props();
432  > ```
433  
434  In turn, annotating the `load` function with `PageLoad`, `PageServerLoad`, `LayoutLoad` or `LayoutServerLoad` (for `+page.js`, `+page.server.js`, `+layout.js` and `+layout.server.js` respectively) ensures that `params` and the return value are correctly typed.
435  
436  If you're using VS Code or any IDE that supports the language server protocol and TypeScript plugins then you can omit these types _entirely_! Svelte's IDE tooling will insert the correct types for you, so you'll get type checking without writing them yourself. It also works with our command line tool `svelte-check`.
437  
438  You can read more about omitting `$types` in our [blog post](/blog/zero-config-type-safety) about it.
439  
440  ## Other files
441  
442  Any other files inside a route directory are ignored by SvelteKit. This means you can colocate components and utility modules with the routes that need them.
443  
444  If components and modules are needed by multiple routes, it's a good idea to put them in [`$lib`]($lib).
445  
446  ## Further reading
447  
448  - [Tutorial: Routing](/tutorial/kit/pages)
449  - [Tutorial: API routes](/tutorial/kit/get-handlers)
450  - [Docs: Advanced routing](advanced-routing)