# Table of Contents - [Introduction • Docs • Svelte](#introduction-docs-svelte) - [Creating a project • Docs • Svelte](#creating-a-project-docs-svelte) - [Project structure • Docs • Svelte](#project-structure-docs-svelte) - [Web standards • Docs • Svelte](#web-standards-docs-svelte) - [Adapters • Docs • Svelte](#adapters-docs-svelte) - [Page options • Docs • Svelte](#page-options-docs-svelte) - [State management • Docs • Svelte](#state-management-docs-svelte) - [Zero-config deployments • Docs • Svelte](#zero-config-deployments-docs-svelte) - [Building your app • Docs • Svelte](#building-your-app-docs-svelte) - [Routing • Docs • Svelte](#routing-docs-svelte) - [Static site generation • Docs • Svelte](#static-site-generation-docs-svelte) - [Single-page apps • Docs • Svelte](#single-page-apps-docs-svelte) - [Cloudflare Pages • Docs • Svelte](#cloudflare-pages-docs-svelte) --- # Introduction • Docs • Svelte [Skip to main content](#main) Before we begin[](#Before-we-begin) ------------------------------------ > If you’re new to Svelte or SvelteKit we recommend checking out the [interactive tutorial](/tutorial/kit) > . > > If you get stuck, reach out for help in the [Discord chatroom](/chat) > . What is SvelteKit?[](#What-is-SvelteKit) ----------------------------------------- SvelteKit is a framework for rapidly developing robust, performant web applications using [Svelte](../svelte) . If you’re coming from React, SvelteKit is similar to Next. If you’re coming from Vue, SvelteKit is similar to Nuxt. To learn more about the kinds of applications you can build with SvelteKit, see the [FAQ](faq#What-can-I-make-with-SvelteKit) . What is Svelte?[](#What-is-Svelte) ----------------------------------- In short, Svelte is a way of writing user interface components — like a navigation bar, comment section, or contact form — that users see and interact with in their browsers. The Svelte compiler converts your components to JavaScript that can be run to render the HTML for the page and to CSS that styles the page. You don’t need to know Svelte to understand the rest of this guide, but it will help. If you’d like to learn more, check out [the Svelte tutorial](/tutorial) . SvelteKit vs Svelte[](#SvelteKit-vs-Svelte) -------------------------------------------- Svelte renders UI components. You can compose these components and render an entire page with just Svelte, but you need more than just Svelte to write an entire app. SvelteKit helps you build web apps while following modern best practices and providing solutions to common development challenges. It offers everything from basic functionalities — like a [router](glossary#Routing) that updates your UI when a link is clicked — to more advanced capabilities. Its extensive list of features includes [build optimizations](https://vitejs.dev/guide/features.html#build-optimizations) to load only the minimal required code; [offline support](service-workers) ; [preloading](link-options#data-sveltekit-preload-data) pages before user navigation; [configurable rendering](page-options) to handle different parts of your app on the server via [SSR](glossary#SSR) , in the browser through [client-side rendering](glossary#CSR) , or at build-time with [prerendering](glossary#Prerendering) ; [image optimization](images) ; and much more. Building an app with all the modern best practices is fiendishly complicated, but SvelteKit does all the boring stuff for you so that you can get on with the creative part. It reflects changes to your code in the browser instantly to provide a lightning-fast and feature-rich development experience by leveraging [Vite](https://vitejs.dev/) with a [Svelte plugin](https://github.com/sveltejs/vite-plugin-svelte) to do [Hot Module Replacement (HMR)](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/config.md#hot) . [Edit this page on GitHub](https://github.com/sveltejs/kit/edit/main/documentation/docs/10-getting-started/10-introduction.md) previous next [Creating a project](/docs/kit/creating-a-project) --- # Creating a project • Docs • Svelte [Skip to main content](#main) The easiest way to start building a SvelteKit app is to run `npx sv create`: npx sv create my-app cd my-app npm install npm run dev The first command will scaffold a new project in the `my-app` directory asking you if you’d like to set up some basic tooling such as TypeScript. See [integrations](./integrations) for pointers on setting up additional tooling. The subsequent commands will then install its dependencies and start a server on [localhost:5173](http://localhost:5173) . There are two basic concepts: * Each page of your app is a [Svelte](../svelte) component * You create pages by adding files to the `src/routes` directory of your project. These will be server-rendered so that a user’s first visit to your app is as fast as possible, then a client-side app takes over Try editing the files to get a feel for how everything works. Editor setup[](#Editor-setup) ------------------------------ We recommend using [Visual Studio Code (aka VS Code)](https://code.visualstudio.com/download) with [the Svelte extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) , but [support also exists for numerous other editors](https://sveltesociety.dev/resources#editor-support) . [Edit this page on GitHub](https://github.com/sveltejs/kit/edit/main/documentation/docs/10-getting-started/20-creating-a-project.md) previous next [Introduction](/docs/kit/introduction) [Project structure](/docs/kit/project-structure) --- # Project structure • Docs • Svelte [Skip to main content](#main) A typical SvelteKit project looks like this: my-project/ ├ src/ │ ├ lib/ │ │ ├ server/ │ │ │ └ [your server-only lib files] │ │ └ [your lib files] │ ├ params/ │ │ └ [your param matchers] │ ├ routes/ │ │ └ [your routes] │ ├ app.html │ ├ error.html │ ├ hooks.client.js │ ├ hooks.server.js │ └ service-worker.js ├ static/ │ └ [your static assets] ├ tests/ │ └ [your tests] ├ package.json ├ svelte.config.js ├ tsconfig.json └ vite.config.js You’ll also find common files like `.gitignore` and `.npmrc` (and `.prettierrc` and `eslint.config.js` and so on, if you chose those options when running `npx sv create`). Project files[](#Project-files) -------------------------------- ### src[](#Project-files-src) The `src` directory contains the meat of your project. Everything except `src/routes` and `src/app.html` is optional. * `lib` contains your library code (utilities and components), which can be imported via the [`$lib`]($lib) alias, or packaged up for distribution using [`svelte-package`](packaging) * `server` contains your server-only library code. It can be imported by using the [`$lib/server`](server-only-modules) alias. SvelteKit will prevent you from importing these in client code. * `params` contains any [param matchers](advanced-routing#Matching) your app needs * `routes` contains the [routes](routing) of your application. You can also colocate other components that are only used within a single route here * `app.html` is your page template — an HTML document containing the following placeholders: * `%sveltekit.head%` — `` and ` src/routes/user/+page

Welcome {user().name}

Welcome {user().name}

> We’re passing a function into `setContext` to keep reactivity across boundaries. Read more about it [here](/docs/svelte/$state#Passing-state-into-functions) > Legacy mode > > You also use stores from `svelte/store` for this, but when using Svelte 5 it is recommended to make use of universal reactivity instead. Updating the value of context-based state in deeper-level pages or components while the page is being rendered via SSR will not affect the value in the parent component because it has already been rendered by the time the state value is updated. In contrast, on the client (when CSR is enabled, which is the default) the value will be propagated and components, pages, and layouts higher in the hierarchy will react to the new value. Therefore, to avoid values ‘flashing’ during state updates during hydration, it is generally recommended to pass state down into components rather than up. If you’re not using SSR (and can guarantee that you won’t need to use SSR in future) then you can safely keep state in a shared module, without using the context API. Component and page state is preserved[](#Component-and-page-state-is-preserved) -------------------------------------------------------------------------------- When you navigate around your application, SvelteKit reuses existing layout and page components. For example, if you have a route like this... src/routes/blog/\[slug\]/+page

{data.title}

Reading time: {Math.round(estimatedReadingTime)} minutes

{@html data.content}

{data.title}

Reading time: {Math.round(estimatedReadingTime)} minutes

{@html data.content}
...then navigating from `/blog/my-short-post` to `/blog/my-long-post` won’t cause the layout, page and any other components within to be destroyed and recreated. Instead the `data` prop (and by extension `data.title` and `data.content`) will update (as it would with any other Svelte component) and, because the code isn’t rerunning, lifecycle methods like `onMount` and `onDestroy` won’t rerun and `estimatedReadingTime` won’t be recalculated. Instead, we need to make the value [_reactive_](/tutorial/svelte/state) : src/routes/blog/\[slug\]/+page > If your code in `onMount` and `onDestroy` has to run again after navigation you can use [afterNavigate]($app-navigation#afterNavigate) > and [beforeNavigate]($app-navigation#beforeNavigate) > respectively. Reusing components like this means that things like sidebar scroll state are preserved, and you can easily animate between changing values. In the case that you do need to completely destroy and remount a component on navigation, you can use this pattern: {#key page.url.pathname} {/key} Storing state in the URL[](#Storing-state-in-the-URL) ------------------------------------------------------ If you have state that should survive a reload and/or affect SSR, such as filters or sorting rules on a table, URL search parameters (like `?sort=price&order=ascending`) are a good place to put them. You can put them in `` or `
` attributes, or set them programmatically via `goto('?key=value')`. They can be accessed inside `load` functions via the `url` parameter, and inside components via `page.url.searchParams`. Storing ephemeral state in snapshots[](#Storing-ephemeral-state-in-snapshots) ------------------------------------------------------------------------------ Some UI state, such as ‘is the accordion open?’, is disposable — if the user navigates away or refreshes the page, it doesn’t matter if the state is lost. In some cases, you _do_ want the data to persist if the user navigates to a different page and comes back, but storing the state in the URL or in a database would be overkill. For this, SvelteKit provides [snapshots](snapshots) , which let you associate component state with a history entry. [Edit this page on GitHub](https://github.com/sveltejs/kit/edit/main/documentation/docs/20-core-concepts/50-state-management.md) previous next [Page options](/docs/kit/page-options) [Building your app](/docs/kit/building-your-app) --- # Zero-config deployments • Docs • Svelte [Skip to main content](#main) When you create a new SvelteKit project with `npx sv create`, it installs [`adapter-auto`](https://github.com/sveltejs/kit/tree/main/packages/adapter-auto) by default. This adapter automatically installs and uses the correct adapter for supported environments when you deploy: * [`@sveltejs/adapter-cloudflare`](adapter-cloudflare) for [Cloudflare Pages](https://developers.cloudflare.com/pages/) * [`@sveltejs/adapter-netlify`](adapter-netlify) for [Netlify](https://netlify.com/) * [`@sveltejs/adapter-vercel`](adapter-vercel) for [Vercel](https://vercel.com/) * [`svelte-adapter-azure-swa`](https://github.com/geoffrich/svelte-adapter-azure-swa) for [Azure Static Web Apps](https://docs.microsoft.com/en-us/azure/static-web-apps/) * [`svelte-kit-sst`](https://github.com/sst/sst/tree/master/packages/svelte-kit-sst) for [AWS via SST](https://sst.dev/docs/start/aws/svelte) * [`@sveltejs/adapter-node`](adapter-node) for [Google Cloud Run](https://cloud.google.com/run) It’s recommended to install the appropriate adapter to your `devDependencies` once you’ve settled on a target environment, since this will add the adapter to your lockfile and slightly improve install times on CI. Environment-specific configuration[](#Environment-specific-configuration) -------------------------------------------------------------------------- To add configuration options, such as `{ edge: true }` in [`adapter-vercel`](adapter-vercel) and [`adapter-netlify`](adapter-netlify) , you must install the underlying adapter — `adapter-auto` does not take any options. Adding community adapters[](#Adding-community-adapters) -------------------------------------------------------- You can add zero-config support for additional adapters by editing [adapters.js](https://github.com/sveltejs/kit/blob/main/packages/adapter-auto/adapters.js) and opening a pull request. [Edit this page on GitHub](https://github.com/sveltejs/kit/edit/main/documentation/docs/25-build-and-deploy/30-adapter-auto.md) previous next [Adapters](/docs/kit/adapters) [Node servers](/docs/kit/adapter-node) --- # Building your app • Docs • Svelte [Skip to main content](#main) Building a SvelteKit app happens in two stages, which both happen when you run `vite build` (usually via `npm run build`). Firstly, Vite creates an optimized production build of your server code, your browser code, and your service worker (if you have one). [Prerendering](page-options#prerender) is executed at this stage, if appropriate. Secondly, an _adapter_ takes this production build and tunes it for your target environment — more on this on the following pages. During the build[](#During-the-build) -------------------------------------- SvelteKit will load your `+page/layout(.server).js` files (and all files they import) for analysis during the build. Any code that should _not_ be executed at this stage must check that `building` from [`$app/environment`]($app-environment) is `false`: import { const building: booleanSvelteKit analyses your app during the build step by running it. During this process, building is true. This also applies during prerendering. building } from '$app/environment'; import { import setupMyDatabasesetupMyDatabase } from '$lib/server/database'; if (!const building: booleanSvelteKit analyses your app during the build step by running it. During this process, building is true. This also applies during prerendering. building) { import setupMyDatabasesetupMyDatabase(); } export function function load(): voidload() { // ... } Preview your app[](#Preview-your-app) -------------------------------------- After building, you can view your production build locally with `vite preview` (via `npm run preview`). Note that this will run the app in Node, and so is not a perfect reproduction of your deployed app — adapter-specific adjustments like the [`platform` object](adapters#Platform-specific-context) do not apply to previews. [Edit this page on GitHub](https://github.com/sveltejs/kit/edit/main/documentation/docs/25-build-and-deploy/10-building-your-app.md) previous next [State management](/docs/kit/state-management) [Adapters](/docs/kit/adapters) --- # Routing • Docs • Svelte [Skip to main content](#main) 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: * `src/routes` is the root route * `src/routes/about` creates an `/about` route * `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` > You can change `src/routes` to a different directory by editing the [project config](configuration) > . Each route directory contains one or more _route files_, which can be identified by their `+` prefix. 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: * All files can run on the server * All files run on the client except `+server` files * `+layout` and `+error` files apply to subdirectories as well as the directory they live in +page[](#page) --------------- ### +page.svelte[](#page-page.svelte) 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. src/routes/+page

Hello and welcome to my site!

About my site src/routes/about/+page

About this site

TODO...

Home Pages can receive data from `load` functions via the `data` prop. src/routes/blog/\[slug\]/+page

{data.title}

{@html data.content}

{data.title}

{@html data.content}
> Legacy mode > > In Svelte 4, you’d use `export let data` instead > SvelteKit uses `` elements to navigate between routes, rather than a framework-specific `` component. ### +page.js[](#page-page.js) 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: src/routes/blog/\[slug\]/+page import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error } from '@sveltejs/kit'; /** @type {import('./$types').PageLoad} */ export function function load({ params }: { params: any; }): { title: string; content: string; }@type{import('./$types').PageLoad}load({ params: anyparams }) { if (params: anyparams.slug === 'hello-world') { return { title: stringtitle: 'Hello world!', content: stringcontent: 'Welcome to our blog. Lorem ipsum dolor sit amet...' }; } function error(status: number, body?: { message: string; } extends App.Error ? App.Error | string | undefined : never): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(404, 'Not found'); } import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error } from '@sveltejs/kit'; import type { type PageLoad = (event: Kit.LoadEvent, Record | null, Record, string | null>) => MaybePromise> type PageLoad = (event: Kit.LoadEvent, Record | null, Record, string | null>) => MaybePromise>PageLoad } from './$types'; export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent, Record | null, Record, string | null>) => MaybePromise> type PageLoad = (event: Kit.LoadEvent, Record | null, Record, string | null>) => MaybePromise>PageLoad = ({ params: RecordThe parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object params }) => { if (params: RecordThe parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object params.slug === 'hello-world') { return { title: stringtitle: 'Hello world!', content: stringcontent: 'Welcome to our blog. Lorem ipsum dolor sit amet...' }; } function error(status: number, body?: { message: string; } extends App.Error ? App.Error | string | undefined : never): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(404, 'Not found'); }; 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. As well as `load`, `+page.js` can export values that configure the page’s behaviour: * `export const prerender = true` or `false` or `'auto'` * `export const ssr = true` or `false` * `export const csr = true` or `false` You can find more information about these in [page options](page-options) . ### +page.server.js[](#page-page.server.js) 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`. src/routes/blog/\[slug\]/+page.server import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error } from '@sveltejs/kit'; /** @type {import('./$types').PageServerLoad} */ export async function function load(event: ServerLoadEvent, Record, string | null>): MaybePromise>@type{import('./$types').PageServerLoad}load({ params: RecordThe parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object params }) { const const post: { title: string; content: string; }post = await const getPostFromDatabase: (slug: string) => { title: string; content: string; }getPostFromDatabase(params: RecordThe parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object params.slug); if (const post: { title: string; content: string; }post) { return const post: { title: string; content: string; }post; } function error(status: number, body?: { message: string; } extends App.Error ? App.Error | string | undefined : never): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(404, 'Not found'); } import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error } from '@sveltejs/kit'; import type { type PageServerLoad = (event: ServerLoadEvent, Record, string | null>) => MaybePromise>PageServerLoad } from './$types'; export const const load: PageServerLoadload: type PageServerLoad = (event: ServerLoadEvent, Record, string | null>) => MaybePromise>PageServerLoad = async ({ params: RecordThe parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object params }) => { const const post: { title: string; content: string; }post = await const getPostFromDatabase: (slug: string) => { title: string; content: string; }getPostFromDatabase(params: RecordThe parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object params.slug); if (const post: { title: string; content: string; }post) { return const post: { title: string; content: string; }post; } function error(status: number, body?: { message: string; } extends App.Error ? App.Error | string | undefined : never): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(404, 'Not found'); }; 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. Like `+page.js`, `+page.server.js` can export [page options](page-options) — `prerender`, `ssr` and `csr`. 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 `` element. To learn how to use them, see the [form actions](form-actions) section. +error[](#error) ----------------- 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: src/routes/blog/\[slug\]/+error

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

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

> Legacy mode > > `$app/state` was added in SvelteKit 2.12. If you’re using an earlier version or are using Svelte 4, use `$app/stores` instead. 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. 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). 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. > `+error.svelte` is _not_ used when an error occurs inside [`handle`](hooks#Server-hooks-handle) > or a [+server.js](#server) > request handler. You can read more about error handling [here](errors) . +layout[](#layout) ------------------- 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. 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_. ### +layout.svelte[](#layout-layout.svelte) 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... {@render children()} ...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: src/routes/+layout
{@render children()} {@render children()} If we create pages for `/`, `/about` and `/settings`... src/routes/+page

Home

src/routes/about/+page

About

src/routes/settings/+page

Settings

...the nav will always be visible, and clicking between the three pages will only result in the `

` being replaced. 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) ). We can create a layout that only applies to pages below `/settings` (while inheriting the root layout with the top-level nav): src/routes/settings/+layout

Settings

{@render children()}

Settings

{@render children()} You can see how `data` is populated by looking at the `+layout.js` example in the next section just below. 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. ### +layout.js[](#layout-layout.js) Just like `+page.svelte` loading data from `+page.js`, your `+layout.svelte` component can get data from a [`load`](load) function in `+layout.js`. src/routes/settings/+layout /** @type {import('./$types').LayoutLoad} */ export function function load(): { sections: { slug: string; title: string; }[]; }@type{import('./$types').LayoutLoad}load() { return { sections: { slug: string; title: string; }[]sections: [\ { slug: stringslug: 'profile', title: stringtitle: 'Profile' },\ { slug: stringslug: 'notifications', title: stringtitle: 'Notifications' }\ ] }; } import type { type LayoutLoad = (event: Kit.LoadEvent, Record | null, Record, string | null>) => MaybePromise> type LayoutLoad = (event: Kit.LoadEvent, Record | null, Record, string | null>) => MaybePromise>LayoutLoad } from './$types'; export const const load: LayoutLoadload: type LayoutLoad = (event: Kit.LoadEvent, Record | null, Record, string | null>) => MaybePromise> type LayoutLoad = (event: Kit.LoadEvent, Record | null, Record, string | null>) => MaybePromise>LayoutLoad = () => { return { sections: { slug: string; title: string; }[]sections: [\ { slug: stringslug: 'profile', title: stringtitle: 'Profile' },\ { slug: stringslug: 'notifications', title: stringtitle: 'Notifications' }\ ] }; }; If a `+layout.js` exports [page options](page-options) — `prerender`, `ssr` and `csr` — they will be used as defaults for child pages. Data returned from a layout’s `load` function is also available to all its child pages: src/routes/settings/profile/+page > Often, layout data is unchanged when navigating between pages. SvelteKit will intelligently rerun [`load`](load) > functions when necessary. ### +layout.server.js[](#layout-layout.server.js) To run your layout’s `load` function on the server, move it to `+layout.server.js`, and change the `LayoutLoad` type to `LayoutServerLoad`. Like `+layout.js`, `+layout.server.js` can export [page options](page-options) — `prerender`, `ssr` and `csr`. +server[](#server) ------------------- 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` argument and return a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. For example we could create an `/api/random-number` route with a `GET` handler: src/routes/api/random-number/+server import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error } from '@sveltejs/kit'; /** @type {import('./$types').RequestHandler} */ export function function GET({ url }: { url: any; }): Response@type{import('./$types').RequestHandler}GET({ url: anyurl }) { const const min: numbermin = var Number: NumberConstructor (value?: any) => numberAn object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers. Number(url: anyurl.searchParams.get('min') ?? '0'); const const max: numbermax = var Number: NumberConstructor (value?: any) => numberAn object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers. Number(url: anyurl.searchParams.get('max') ?? '1'); const const d: numberd = const max: numbermax - const min: numbermin; if (function isNaN(number: number): booleanReturns a Boolean value that indicates whether a value is the reserved value NaN (not a number). @paramnumber A numeric value.isNaN(const d: numberd) || const d: numberd < 0) { function error(status: number, body?: { message: string; } extends App.Error ? App.Error | string | undefined : never): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(400, 'min and max must be numbers, and min must be less than max'); } const const random: numberrandom = const min: numbermin + var Math: MathAn intrinsic object that provides basic mathematics functionality and constants. Math.Math.random(): numberReturns a pseudorandom number between 0 and 1. random() * const d: numberd; return new var Response: new (body?: BodyInit | null, init?: ResponseInit) => ResponseThis Fetch API interface represents the response to a request. MDN Reference Response(var String: StringConstructor (value?: any) => stringAllows manipulation and formatting of text strings and determination and location of substrings within strings. String(const random: numberrandom)); } import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error } from '@sveltejs/kit'; import type { type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromise type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromiseRequestHandler } from './$types'; export const const GET: RequestHandlerGET: type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromise type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromiseRequestHandler = ({ url: URLThe requested URL. url }) => { const const min: numbermin = var Number: NumberConstructor (value?: any) => numberAn object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers. Number(url: URLThe requested URL. url.URL.searchParams: URLSearchParamsMDN Reference searchParams.URLSearchParams.get(name: string): string | nullReturns the first value associated to the given search parameter. MDN Reference get('min') ?? '0'); const const max: numbermax = var Number: NumberConstructor (value?: any) => numberAn object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers. Number(url: URLThe requested URL. url.URL.searchParams: URLSearchParamsMDN Reference searchParams.URLSearchParams.get(name: string): string | nullReturns the first value associated to the given search parameter. MDN Reference get('max') ?? '1'); const const d: numberd = const max: numbermax - const min: numbermin; if (function isNaN(number: number): booleanReturns a Boolean value that indicates whether a value is the reserved value NaN (not a number). @paramnumber A numeric value.isNaN(const d: numberd) || const d: numberd < 0) { function error(status: number, body?: { message: string; } extends App.Error ? App.Error | string | undefined : never): never (+1 overload)Throws an error with a HTTP status code and an optional message. When called during request handling, this will cause SvelteKit to return an error response without invoking handleError. Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it. @paramstatus The HTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(400, 'min and max must be numbers, and min must be less than max'); } const const random: numberrandom = const min: numbermin + var Math: MathAn intrinsic object that provides basic mathematics functionality and constants. Math.Math.random(): numberReturns a pseudorandom number between 0 and 1. random() * const d: numberd; return new var Response: new (body?: BodyInit | null, init?: ResponseInit) => ResponseThis Fetch API interface represents the response to a request. MDN Reference Response(var String: StringConstructor (value?: any) => stringAllows manipulation and formatting of text strings and determination and location of substrings within strings. String(const random: numberrandom)); }; 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). 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). 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) . > 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. > `+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. ### Receiving data[](#server-Receiving-data) By exporting `POST` / `PUT`/`PATCH`/`DELETE`/`OPTIONS`/`HEAD` handlers, `+server.js` files can be used to create a complete API: src/routes/add/+page + = {total} + = {total} src/routes/api/add/+server import { function json(data: any, init?: ResponseInit | undefined): ResponseCreate a JSON Response object from the supplied data. @paramdata The value that will be serialized as JSON.@paraminit Options such as status and headers that will be added to the response. Content-Type: application/json and Content-Length headers will be added automatically.json } from '@sveltejs/kit'; /** @type {import('./$types').RequestHandler} */ export async function function POST({ request }: { request: any; }): Promise@type{import('./$types').RequestHandler}POST({ request: anyrequest }) { const { const a: anya, const b: anyb } = await request: anyrequest.json(); return function json(data: any, init?: ResponseInit | undefined): ResponseCreate a JSON Response object from the supplied data. @paramdata The value that will be serialized as JSON.@paraminit Options such as status and headers that will be added to the response. Content-Type: application/json and Content-Length headers will be added automatically.json(const a: anya + const b: anyb); } import { function json(data: any, init?: ResponseInit | undefined): ResponseCreate a JSON Response object from the supplied data. @paramdata The value that will be serialized as JSON.@paraminit Options such as status and headers that will be added to the response. Content-Type: application/json and Content-Length headers will be added automatically.json } from '@sveltejs/kit'; import type { type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromise type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromiseRequestHandler } from './$types'; export const const POST: RequestHandlerPOST: type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromise type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromiseRequestHandler = async ({ request: RequestThe original request object request }) => { const { const a: anya, const b: anyb } = await request: RequestThe original request object request.Body.json(): PromiseMDN Reference json(); return function json(data: any, init?: ResponseInit | undefined): ResponseCreate a JSON Response object from the supplied data. @paramdata The value that will be serialized as JSON.@paraminit Options such as status and headers that will be added to the response. Content-Type: application/json and Content-Length headers will be added automatically.json(const a: anya + const b: anyb); }; > In general, [form actions](form-actions) > are a better way to submit data from the browser to the server. > If a `GET` handler is exported, a `HEAD` request will return the `content-length` of the `GET` handler’s response body. ### Fallback method handler[](#server-Fallback-method-handler) Exporting the `fallback` handler will match any unhandled request methods, including methods like `MOVE` which have no dedicated export from `+server.js`. src/routes/api/add/+server import { function json(data: any, init?: ResponseInit | undefined): ResponseCreate a JSON Response object from the supplied data. @paramdata The value that will be serialized as JSON.@paraminit Options such as status and headers that will be added to the response. Content-Type: application/json and Content-Length headers will be added automatically.json, function text(body: string, init?: ResponseInit | undefined): ResponseCreate a Response object from the supplied body. @parambody The value that will be used as-is.@paraminit Options such as status and headers that will be added to the response. A Content-Length header will be added automatically.text } from '@sveltejs/kit'; export async function function POST({ request }: { request: any; }): PromisePOST({ request: anyrequest }) { const { const a: anya, const b: anyb } = await request: anyrequest.json(); return function json(data: any, init?: ResponseInit | undefined): ResponseCreate a JSON Response object from the supplied data. @paramdata The value that will be serialized as JSON.@paraminit Options such as status and headers that will be added to the response. Content-Type: application/json and Content-Length headers will be added automatically.json(const a: anya + const b: anyb); } // This handler will respond to PUT, PATCH, DELETE, etc. /** @type {import('./$types').RequestHandler} */ export async function function fallback({ request }: { request: any; }): Promise@type{import('./$types').RequestHandler}fallback({ request: anyrequest }) { return function text(body: string, init?: ResponseInit | undefined): ResponseCreate a Response object from the supplied body. @parambody The value that will be used as-is.@paraminit Options such as status and headers that will be added to the response. A Content-Length header will be added automatically.text(`I caught your ${request: anyrequest.method} request!`); } import { function json(data: any, init?: ResponseInit | undefined): ResponseCreate a JSON Response object from the supplied data. @paramdata The value that will be serialized as JSON.@paraminit Options such as status and headers that will be added to the response. Content-Type: application/json and Content-Length headers will be added automatically.json, function text(body: string, init?: ResponseInit | undefined): ResponseCreate a Response object from the supplied body. @parambody The value that will be used as-is.@paraminit Options such as status and headers that will be added to the response. A Content-Length header will be added automatically.text } from '@sveltejs/kit'; import type { type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromise type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromiseRequestHandler } from './$types'; export async function function POST({ request }: { request: any; }): PromisePOST({ request: anyrequest }) { const { const a: anya, const b: anyb } = await request: anyrequest.json(); return function json(data: any, init?: ResponseInit | undefined): ResponseCreate a JSON Response object from the supplied data. @paramdata The value that will be serialized as JSON.@paraminit Options such as status and headers that will be added to the response. Content-Type: application/json and Content-Length headers will be added automatically.json(const a: anya + const b: anyb); } // This handler will respond to PUT, PATCH, DELETE, etc. export const const fallback: RequestHandlerfallback: type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromise type RequestHandler = (event: Kit.RequestEvent, string | null>) => MaybePromiseRequestHandler = async ({ request: RequestThe original request object request }) => { return function text(body: string, init?: ResponseInit | undefined): ResponseCreate a Response object from the supplied body. @parambody The value that will be used as-is.@paraminit Options such as status and headers that will be added to the response. A Content-Length header will be added automatically.text(`I caught your ${request: RequestThe original request object request.Request.method: stringReturns request’s HTTP method, which is “GET” by default. MDN Reference method} request!`); }; > For `HEAD` requests, the `GET` handler takes precedence over the `fallback` handler. ### Content negotiation[](#server-Content-negotiation) `+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: * `PUT` / `PATCH`/`DELETE`/`OPTIONS` requests are always handled by `+server.js` since they do not apply to pages * `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`. * Responses to `GET` requests will include a `Vary: Accept` header, so that proxies and browsers cache HTML and JSON responses separately. $types[](#$types) ------------------ 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. For example, annotating `let { data } = $props()` with `PageData` (or `LayoutData`, for a `+layout.svelte` file) tells TypeScript that the type of `data` is whatever was returned from `load`: src/routes/blog/\[slug\]/+page 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. 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`. You can read more about omitting `$types` in our [blog post](/blog/zero-config-type-safety) about it. Other files[](#Other-files) ---------------------------- 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. If components and modules are needed by multiple routes, it’s a good idea to put them in [`$lib`]($lib) . Further reading[](#Further-reading) ------------------------------------ * [Tutorial: Routing](/tutorial/kit/pages) * [Tutorial: API routes](/tutorial/kit/get-handlers) * [Docs: Advanced routing](advanced-routing) [Edit this page on GitHub](https://github.com/sveltejs/kit/edit/main/documentation/docs/20-core-concepts/10-routing.md) previous next [Web standards](/docs/kit/web-standards) [Loading data](/docs/kit/load) --- # Static site generation • Docs • Svelte [Skip to main content](#main) To use SvelteKit as a static site generator (SSG), use [`adapter-static`](https://github.com/sveltejs/kit/tree/main/packages/adapter-static) . This will prerender your entire site as a collection of static files. If you’d like to prerender only some pages and dynamically server-render others, you will need to use a different adapter together with [the `prerender` option](page-options#prerender) . Usage[](#Usage) ---------------- Install with `npm i -D @sveltejs/adapter-static`, then add the adapter to your `svelte.config.js`: svelte.config import import adapteradapter from '@sveltejs/adapter-static'; export default { kit: { adapter: any; }kit: { adapter: anyadapter: import adapteradapter({ // default options are shown. On some platforms // these options are set automatically — see below pages: stringpages: 'build', assets: stringassets: 'build', fallback: undefinedfallback: var undefinedundefined, precompress: booleanprecompress: false, strict: booleanstrict: true }) } }; ...and add the [`prerender`](page-options#prerender) option to your root layout: src/routes/+layout // This can be false if you're using a fallback (i.e. SPA mode) export const const prerender: trueprerender = true; > You must ensure SvelteKit’s [`trailingSlash`](page-options#trailingSlash) > option is set appropriately for your environment. If your host does not render `/a.html` upon receiving a request for `/a` then you will need to set `trailingSlash: 'always'` in your root layout to create `/a/index.html` instead. Zero-config support[](#Zero-config-support) -------------------------------------------- Some platforms have zero-config support (more to come in future): * [Vercel](https://vercel.com) On these platforms, you should omit the adapter options so that `adapter-static` can provide the optimal configuration: svelte.config export default { kit: { adapter: any; }kit: { adapter: anyadapter: adapter({...}) } }; Options[](#Options) -------------------- ### pages[](#Options-pages) The directory to write prerendered pages to. It defaults to `build`. ### assets[](#Options-assets) The directory to write static assets (the contents of `static`, plus client-side JS and CSS generated by SvelteKit) to. Ordinarily this should be the same as `pages`, and it will default to whatever the value of `pages` is, but in rare circumstances you might need to output pages and assets to separate locations. ### fallback[](#Options-fallback) Specify a fallback page for [SPA mode](single-page-apps) , e.g. `index.html` or `200.html` or `404.html`. ### precompress[](#Options-precompress) If `true`, precompresses files with brotli and gzip. This will generate `.br` and `.gz` files. ### strict[](#Options-strict) By default, `adapter-static` checks that either all pages and endpoints (if any) of your app were prerendered, or you have the `fallback` option set. This check exists to prevent you from accidentally publishing an app where some parts of it are not accessible, because they are not contained in the final output. If you know this is ok (for example when a certain page only exists conditionally), you can set `strict` to `false` to turn off this check. GitHub Pages[](#GitHub-Pages) ------------------------------ When building for [GitHub Pages](https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages) , if your repo name is not equivalent to `your-username.github.io`, make sure to update [`config.kit.paths.base`](configuration#paths) to match your repo name. This is because the site will be served from `https://your-username.github.io/your-repo-name` rather than from the root. You’ll also want to generate a fallback `404.html` page to replace the default 404 page shown by GitHub Pages. A config for GitHub Pages might look like the following: svelte.config import import adapteradapter from '@sveltejs/adapter-static'; /** @type {import('@sveltejs/kit').Config} */ const const config: { kit: { adapter: any; paths: { base: string | undefined; }; }; }@type{import('@sveltejs/kit').Config}config = { kit: { adapter: any; paths: { base: string | undefined; }; }kit: { adapter: anyadapter: import adapteradapter({ fallback: stringfallback: '404.html' }), paths: { base: string | undefined; }paths: { base: string | undefinedbase: var process: NodeJS.Processprocess.NodeJS.Process.argv: string[]The process.argv property returns an array containing the command-line arguments passed when the Node.js process was launched. The first element will be {@link execPath } . See process.argv0 if access to the original value of argv[0] is needed. The second element will be the path to the JavaScript file being executed. The remaining elements will be any additional command-line arguments. For example, assuming the following script for process-args.js: import { argv } from 'node:process'; // print process.argv argv.forEach((val, index) => { console.log(`${index}: ${val}`); });Launching the Node.js process as: node process-args.js one two=three fourWould generate the output: 0: /usr/local/bin/node 1: /Users/mjr/work/node/process-args.js 2: one 3: two=three 4: four@sincev0.1.27argv.Array.includes(searchElement: string, fromIndex?: number): booleanDetermines whether an array includes a certain element, returning true or false as appropriate. @paramsearchElement The element to search for.@paramfromIndex The position in this array at which to begin searching for searchElement.includes('dev') ? '' : var process: NodeJS.Processprocess.NodeJS.Process.env: NodeJS.ProcessEnvThe process.env property returns an object containing the user environment. See environ(7). An example of this object looks like: { TERM: 'xterm-256color', SHELL: '/usr/local/bin/bash', USER: 'maciej', PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin', PWD: '/Users/maciej', EDITOR: 'vim', SHLVL: '1', HOME: '/Users/maciej', LOGNAME: 'maciej', _: '/usr/local/bin/node' }It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other Worker threads. In other words, the following example would not work: node -e 'process.env.foo = "bar"' &#x26;&#x26; echo $fooWhile the following will: import { env } from 'node:process'; env.foo = 'bar'; console.log(env.foo);Assigning a property on process.env will implicitly convert the value to a string. This behavior is deprecated. Future versions of Node.js may throw an error when the value is not a string, number, or boolean. import { env } from 'node:process'; env.test = null; console.log(env.test); // => 'null' env.test = undefined; console.log(env.test); // => 'undefined'Use delete to delete a property from process.env. import { env } from 'node:process'; env.TEST = 1; delete env.TEST; console.log(env.TEST); // => undefinedOn Windows operating systems, environment variables are case-insensitive. import { env } from 'node:process'; env.TEST = 1; console.log(env.test); // => 1Unless explicitly specified when creating a Worker instance, each Worker thread has its own copy of process.env, based on its parent thread’s process.env, or whatever was specified as the env option to the Worker constructor. Changes to process.env will not be visible across Worker threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of process.env on a Worker instance operates in a case-sensitive manner unlike the main thread. @sincev0.1.27env.string | undefinedBASE_PATH } } }; export default const config: { kit: { adapter: any; paths: { base: string | undefined; }; }; }@type{import('@sveltejs/kit').Config}config; You can use GitHub actions to automatically deploy your site to GitHub Pages when you make a change. Here’s an example workflow: .github/workflows/deploy name: Deploy to GitHub Pages on: push: branches: 'main' jobs: build_site: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 # If you're using pnpm, add this step then change the commands and cache key below to use `pnpm` # - name: Install pnpm # uses: pnpm/action-setup@v3 # with: # version: 8 - name: Install Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: npm - name: Install dependencies run: npm install - name: build env: BASE_PATH: '/${{ github.event.repository.name }}' run: | npm run build - name: Upload Artifacts uses: actions/upload-pages-artifact@v3 with: # this should match the `pages` option in your adapter-static options path: 'build/' deploy: needs: build_site runs-on: ubuntu-latest permissions: pages: write id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy id: deployment uses: actions/deploy-pages@v4 If you’re not using GitHub actions to deploy your site (for example, you’re pushing the built site to its own repo), add an empty `.nojekyll` file in your `static` directory to prevent Jekyll from interfering. [Edit this page on GitHub](https://github.com/sveltejs/kit/edit/main/documentation/docs/25-build-and-deploy/50-adapter-static.md) previous next [Node servers](/docs/kit/adapter-node) [Single-page apps](/docs/kit/single-page-apps) --- # Single-page apps • Docs • Svelte [Skip to main content](#main) You can turn any SvelteKit app, using any adapter, into a fully client-rendered single-page app (SPA) by disabling SSR at the root layout: src/routes/+layout export const const ssr: falsessr = false; > In most situations this is not recommended: it harms SEO, tends to slow down perceived performance, and makes your app inaccessible to users if JavaScript fails or is disabled (which happens [more often than you probably think](https://kryogenix.org/code/browser/everyonehasjs.html) > ). If you don’t have any server-side logic (i.e. `+page.server.js`, `+layout.server.js` or `+server.js` files) you can use [`adapter-static`](adapter-static) to create your SPA by adding a _fallback page_. Usage[](#Usage) ---------------- Install with `npm i -D @sveltejs/adapter-static`, then add the adapter to your `svelte.config.js` with the following options: svelte.config import import adapteradapter from '@sveltejs/adapter-static'; export default { kit: { adapter: any; }kit: { adapter: anyadapter: import adapteradapter({ fallback: stringfallback: '200.html' // may differ from host to host }) } }; The `fallback` page is an HTML page created by SvelteKit from your page template (e.g. `app.html`) that loads your app and navigates to the correct route. For example [Surge](https://surge.sh/help/adding-a-200-page-for-client-side-routing) , a static web host, lets you add a `200.html` file that will handle any requests that don’t correspond to static assets or prerendered pages. On some hosts it may be `index.html` or something else entirely — consult your platform’s documentation. > Note that the fallback page will always contain absolute asset paths (i.e. beginning with `/` rather than `.`) regardless of the value of [`paths.relative`](configuration#paths) > , since it is used to respond to requests for arbitrary paths. Apache[](#Apache) ------------------ To run an SPA on [Apache](https://httpd.apache.org/) , you should add a `static/.htaccess` file to route requests to the fallback page: RewriteEngine On RewriteBase / RewriteRule ^200\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /200.html [L] Prerendering individual pages[](#Prerendering-individual-pages) ---------------------------------------------------------------- If you want certain pages to be prerendered, you can re-enable `ssr` alongside `prerender` for just those parts of your app: src/routes/my-prerendered-page/+page export const const prerender: trueprerender = true; export const const ssr: truessr = true; [Edit this page on GitHub](https://github.com/sveltejs/kit/edit/main/documentation/docs/25-build-and-deploy/55-single-page-apps.md) previous next [Static site generation](/docs/kit/adapter-static) [Cloudflare Pages](/docs/kit/adapter-cloudflare) --- # Cloudflare Pages • Docs • Svelte [Skip to main content](#main) To deploy to [Cloudflare Pages](https://developers.cloudflare.com/pages/) , use [`adapter-cloudflare`](https://github.com/sveltejs/kit/tree/main/packages/adapter-cloudflare) . This adapter will be installed by default when you use [`adapter-auto`](adapter-auto) . If you plan on staying with Cloudflare Pages, you can switch from [`adapter-auto`](adapter-auto) to using this adapter directly so that values specific to Cloudflare Workers are emulated during local development, type declarations are automatically applied, and the ability to set Cloudflare-specific options is provided. Comparisons[](#Comparisons) ---------------------------- * `adapter-cloudflare` – supports all SvelteKit features; builds for [Cloudflare Pages](https://blog.cloudflare.com/cloudflare-pages-goes-full-stack/) * `adapter-cloudflare-workers` – supports all SvelteKit features; builds for Cloudflare Workers * `adapter-static` – only produces client-side static assets; compatible with Cloudflare Pages Usage[](#Usage) ---------------- Install with `npm i -D @sveltejs/adapter-cloudflare`, then add the adapter to your `svelte.config.js`: svelte.config import import adapteradapter from '@sveltejs/adapter-cloudflare'; export default { kit: { adapter: any; }kit: { adapter: anyadapter: import adapteradapter({ // See below for an explanation of these options routes: { include: string[]; exclude: string[]; }routes: { include: string[]include: ['/*'], exclude: string[]exclude: [''] }, platformProxy: { configPath: string; environment: undefined; experimentalJsonConfig: boolean; persist: boolean; }platformProxy: { configPath: stringconfigPath: 'wrangler.toml', environment: undefinedenvironment: var undefinedundefined, experimentalJsonConfig: booleanexperimentalJsonConfig: false, persist: booleanpersist: false } }) } }; Options[](#Options) -------------------- ### routes[](#Options-routes) Allows you to customise the [`_routes.json`](https://developers.cloudflare.com/pages/platform/functions/routing/#create-a-_routesjson-file) file generated by `adapter-cloudflare`. * `include` defines routes that will invoke a function, and defaults to `['/*']` * `exclude` defines routes that will _not_ invoke a function — this is a faster and cheaper way to serve your app’s static assets. This array can include the following special values: * `` contains your app’s build artifacts (the files generated by Vite) * `` contains the contents of your `static` directory * `` contains a list of prerendered pages * `` (the default) contains all of the above You can have up to 100 `include` and `exclude` rules combined. Generally you can omit the `routes` options, but if (for example) your `` paths exceed that limit, you may find it helpful to manually create an `exclude` list that includes `'/articles/*'` instead of the auto-generated `['/articles/foo', '/articles/bar', '/articles/baz', ...]`. ### platformProxy[](#Options-platformProxy) Preferences for the emulated `platform.env` local bindings. See the [getPlatformProxy](https://developers.cloudflare.com/workers/wrangler/api/#syntax) Wrangler API documentation for a full list of options. Deployment[](#Deployment) -------------------------- Please follow the [Get Started Guide](https://developers.cloudflare.com/pages/get-started) for Cloudflare Pages to begin. When configuring your project settings, you must use the following settings: * **Framework preset** – SvelteKit * **Build command** – `npm run build` or `vite build` * **Build output directory** – `.svelte-kit/cloudflare` Runtime APIs[](#Runtime-APIs) ------------------------------ The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object contains your project’s [bindings](https://developers.cloudflare.com/pages/platform/functions/bindings/) , which consist of KV/DO namespaces, etc. It is passed to SvelteKit via the `platform` property, along with [`context`](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#contextwaituntil) , [`caches`](https://developers.cloudflare.com/workers/runtime-apis/cache/) , and [`cf`](https://developers.cloudflare.com/workers/runtime-apis/request/#the-cf-property-requestinitcfproperties) , meaning that you can access it in hooks and endpoints: export async function function POST({ request, platform }: { request: any; platform: any; }): PromisePOST({ request, platform }) { const const x: anyx = platform: anyplatform.env.YOUR_DURABLE_OBJECT_NAMESPACE.idFromName('x'); } > SvelteKit’s built-in `$env` module should be preferred for environment variables. To include type declarations for your bindings, reference them in your `src/app.d.ts`: src/app.d import { interface KVNamespaceKVNamespace, interface DurableObjectNamespaceDurableObjectNamespace } from '@cloudflare/workers-types'; declare global { namespace App { interface interface App.PlatformIf your adapter provides platform-specific context via event.platform, you can specify it here. Platform { App.Platform.env?: { YOUR_KV_NAMESPACE: KVNamespace; YOUR_DURABLE_OBJECT_NAMESPACE: DurableObjectNamespace; } | undefinedenv?: { type YOUR_KV_NAMESPACE: KVNamespaceYOUR_KV_NAMESPACE: interface KVNamespaceKVNamespace; type YOUR_DURABLE_OBJECT_NAMESPACE: DurableObjectNamespaceYOUR_DURABLE_OBJECT_NAMESPACE: interface DurableObjectNamespaceDurableObjectNamespace; }; } } } export {}; ### Testing Locally[](#Runtime-APIs-Testing-Locally) Cloudflare Workers specific values in the `platform` property are emulated during dev and preview modes. Local [bindings](https://developers.cloudflare.com/workers/wrangler/configuration/#bindings) are created based on the configuration in your `wrangler.toml` file and are used to populate `platform.env` during development and preview. Use the adapter config [`platformProxy` option](#Options-platformProxy) to change your preferences for the bindings. For testing the build, you should use [wrangler](https://developers.cloudflare.com/workers/cli-wrangler) **version 3**. Once you have built your site, run `wrangler pages dev .svelte-kit/cloudflare`. Notes[](#Notes) ---------------- Functions contained in the `/functions` directory at the project’s root will _not_ be included in the deployment, which is compiled to a [single `_worker.js` file](https://developers.cloudflare.com/pages/platform/functions/#advanced-mode) . Functions should be implemented as [server endpoints](routing#server) in your SvelteKit app. The `_headers` and `_redirects` files specific to Cloudflare Pages can be used for static asset responses (like images) by putting them into the `/static` folder. However, they will have no effect on responses dynamically rendered by SvelteKit, which should return custom headers or redirect responses from [server endpoints](routing#server) or with the [`handle`](hooks#Server-hooks-handle) hook. Troubleshooting[](#Troubleshooting) ------------------------------------ ### Further reading[](#Troubleshooting-Further-reading) You may wish to refer to [Cloudflare’s documentation for deploying a SvelteKit site](https://developers.cloudflare.com/pages/framework-guides/deploy-a-svelte-site) . ### Accessing the file system[](#Troubleshooting-Accessing-the-file-system) You can’t use `fs` in Cloudflare Workers — you must [prerender](page-options#prerender) the routes in question. [Edit this page on GitHub](https://github.com/sveltejs/kit/edit/main/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md) previous next [Single-page apps](/docs/kit/single-page-apps) [Cloudflare Workers](/docs/kit/adapter-cloudflare-workers) ---