Documentation

Introduction permalink

Before we begin

SvelteKit is in early development, and some things may change before we hit version 1.0. This document is a work-in-progress. If you get stuck, reach out for help in the Discord chatroom.

See the migration guides for help upgrading from Sapper.

What is SvelteKit?

SvelteKit is a framework for building extremely high-performance web apps. You're looking at one right now! There are two basic concepts:

  • Each page of your app is a 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

Building an app with all the modern best practices — code-splitting, offline support, server-rendered views with client-side hydration — is fiendishly complicated. SvelteKit does all the boring stuff for you so that you can get on with the creative part.

You don't need to know Svelte to understand the rest of this guide, but it will help. In short, it's a UI framework that compiles your components to highly optimized vanilla JavaScript. Read the introductory blog post and the tutorial to learn more.

Getting started

The easiest way to start building a SvelteKit app is to run npm init:

npm init svelte@next my-app
cd my-app
npm install
npm run dev

This will scaffold a new project in the my-app directory, install its dependencies, and start a server on localhost:3000. Try editing the files to get a feel for how everything works – you may not need to bother reading the rest of this guide!

Routing permalink

At the heart of SvelteKit is a filesystem-based router. This means that the structure of your application is defined by the structure of your codebase — specifically, the contents of src/routes.

You can change this to a different directory by editing the project config.

There are two types of route — pages and endpoints.

Pages typically generate HTML to display to the user (as well as any CSS and JavaScript needed for the page). By default, pages are rendered on both the client and server, though this behaviour is configurable.

Endpoints run only on the server (or when you build your site, if prerendering). This means it's the place to do things like access databases or APIs that require private credentials or return data that lives on a machine in your production network. Pages can request data from endpoints. Endpoints return JSON by default, though may also return data in other formats.

Pages

Pages are Svelte components written in .svelte files (or any file with an extension listed in config.extensions). By default, when a user first visits the application, they will be served a server-rendered version of the page in question, plus some JavaScript that 'hydrates' the page and initialises a client-side router. From that point forward, navigating to other pages is handled entirely on the client for a fast, app-like feel where the common portions in the layout do not need to be rerendered.

The filename determines the route. For example, src/routes/index.svelte is the root of your site:

<!-- src/routes/index.svelte -->
<svelte:head>
	<title>Welcome</title>
</svelte:head>

<h1>Hello and welcome to my site!</h1>

A file called either src/routes/about.svelte or src/routes/about/index.svelte would correspond to the /about route:

<!-- src/routes/about.svelte -->
<svelte:head>
	<title>About</title>
</svelte:head>

<h1>About this site</h1>
<p>TODO...</p>

Dynamic parameters are encoded using [brackets]. For example, a blog post might be defined by src/routes/blog/[slug].svelte. Soon, we'll see how to access that parameter in a load function or the page store.

A file or directory can have multiple dynamic parts, like [id]-[category].svelte. (Parameters are 'non-greedy'; in an ambiguous case like x-y-z, id would be x and category would be y-z.)

Endpoints

Endpoints are modules written in .js (or .ts) files that export functions corresponding to HTTP methods.

// Endpoint TypeScript type definitions

type Headers = Record<string, string>;
type DefaultBody = JSONValue | Uint8Array;

type Request<Locals = Record<string, any>, Body = unknown> = {
	method: string;
	host: string;
	headers: Headers;
	path: string;
	params: Record<string, string>;
	query: URLSearchParams;
	rawBody: string | Uint8Array;
	body: ParameterizedBody<Body>;
	locals: Locals; // populated by hooks handle
};

type EndpointOutput<Body extends DefaultBody = DefaultBody> = {
	status?: number;
	headers?: Headers;
	body?: Body;
};

type RequestHandler<
	Locals = Record<string, any>,
	Input = unknown,
	Output extends DefaultBody = DefaultBody
> = (
	request: Request<Locals, Input>
) => void | EndpointOutput<Output> | Promise<void | EndpointOutput<Output>>;

For example, our hypothetical blog page, /blog/cool-article, might request data from /blog/cool-article.json, which could be represented by a src/routes/blog/[slug].json.js endpoint:

import db from '$lib/database';

/**
 * @type {import('@sveltejs/kit').RequestHandler}
 */
export async function get({ params }) {
	// the `slug` parameter is available because this file
	// is called [slug].json.js
	const { slug } = params;

	const article = await db.get(slug);

	if (article) {
return {
	body: {
		article
	}
};
	}
}

All server-side code, including endpoints, has access to fetch in case you need to request data from external APIs.

The job of this function is to return a { status, headers, body } object representing the response, where status is an HTTP status code:

  • 2xx — successful response (default is 200)
  • 3xx — redirection (should be accompanied by a location header)
  • 4xx — client error
  • 5xx — server error

For successful responses, SvelteKit will generate 304s automatically.

If the returned body is an object, and no content-type header is returned, it will automatically be turned into a JSON response. (Don't worry about $lib, we'll get to that later.)

Returning nothing is equivalent to an explicit 404 response.

For endpoints that handle other HTTP methods, like POST, export the corresponding function:

export function post(request) {...}

Since delete is a reserved word in JavaScript, DELETE requests are handled with a del function.

We don't interact with the req/res objects you might be familiar with from Node's http module or frameworks like Express, because they're only available on certain platforms. Instead, SvelteKit translates the returned object into whatever's required by the platform you're deploying your app to.

To set multiple cookies in a single set of response headers, you can return an array:

return {
	headers: {
'set-cookie': [cookie1, cookie2]
	}
};

Body parsing

The body property of the request object will be provided in the case of POST requests:

  • Text data (with content-type text/plain) will be parsed to a string
  • JSON data (with content-type application/json) will be parsed to a JSONValue (an object, Array, or primitive).
  • Form data (with content-type application/x-www-form-urlencoded or multipart/form-data) will be parsed to a read-only version of the FormData object.
  • All other data will be provided as a Uint8Array

Private modules

A filename that has a segment with a leading underscore, such as src/routes/foo/_Private.svelte or src/routes/bar/_utils/cool-util.js, is hidden from the router, but can be imported by files that are not.

Advanced

Rest parameters

A route can have multiple dynamic parameters, for example src/routes/[category]/[item].svelte or even src/routes/[category]-[item].svelte. If the number of route segments is unknown, you can use rest syntax — for example you might implement GitHub's file viewer like so...

/[org]/[repo]/tree/[branch]/[...file]

...in which case a request for /sveltejs/kit/tree/master/documentation/docs/01-routing.md would result in the following parameters being available to the page:

{
	org: 'sveltejs',
	repo: 'kit',
	branch: 'master',
	file: 'documentation/docs/01-routing.md'
}

src/routes/a/[...rest]/z.svelte will match /a/z as well as /a/b/z and /a/b/c/z and so on. Make sure you check that the value of the rest parameter is valid.

Fallthrough routes

Finally, if you have multiple routes that match a given path, SvelteKit will try each of them until one responds. For example if you have these routes...

src/routes/[baz].js
src/routes/[baz].svelte
src/routes/[qux].svelte
src/routes/foo-[bar].svelte

...and you navigate to /foo-xyz, then SvelteKit will first try foo-[bar].svelte because it is the best match, then will try [baz].js (which is also a valid match for /foo-xyz, but less specific), then [baz].svelte and [qux].svelte in alphabetical order (endpoints have higher precedence than pages). The first route that responds — a page that returns something from load or has no load function, or an endpoint that returns something — will handle the request.

If no page or endpoint responds to a request, SvelteKit will respond with a generic 404.

Layouts permalink

So far, we've treated pages as entirely standalone components — upon navigation, the existing 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, we can use layout components.

To create a layout component that applies to every page, make a file called src/routes/__layout.svelte. The default layout component (the one that SvelteKit uses if you don't bring your own) looks like this...

<slot></slot>

...but we can add whatever markup, styles and behaviour we want. The only requirement is that the component includes a <slot> for the page content. For example, let's add a nav bar:

<!-- src/routes/__layout.svelte -->
<nav>
	<a href=".">Home</a>
	<a href="about">About</a>
	<a href="settings">Settings</a>
</nav>

<slot></slot>

If we create pages for /, /about and /settings...

<!-- src/routes/index.svelte -->
<h1>Home</h1>
<!-- src/routes/about.svelte -->
<h1>About</h1>
<!-- src/routes/settings.svelte -->
<h1>Settings</h1>

...the nav will always be visible, and clicking between the three pages will only result in the <h1> being replaced.

Nested layouts

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).

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.svelte -->
<h1>Settings</h1>

<div class="submenu">
	<a href="/settings/profile">Profile</a>
	<a href="/settings/notifications">Notifications</a>
</div>

<slot></slot>

Resets

To reset the layout stack, create a __layout.reset.svelte file instead of a __layout.svelte file. For example, if you want your /admin/* pages to not inherit the root layout, create a file called src/routes/admin/__layout.reset.svelte.

Layout resets are otherwise identical to normal layout components.

Error pages

If a page fails to load (see Loading), SvelteKit will render an error page. You can customise this page by creating __error.svelte components alongside your layout and page components.

For example, if src/routes/settings/notifications/index.svelte failed to load, SvelteKit would render src/routes/settings/notifications/__error.svelte in the same layout, if it existed. If not, it would render src/routes/settings/__error.svelte in the parent layout, or src/routes/__error.svelte in the root layout.

SvelteKit provides a default error page in case you don't supply src/routes/__error.svelte, but it's recommended that you bring your own.

If an error component has a load function, it will be called with error and status properties:

<script context="module">
	export function load({ error, status }) {
return {
	props: {
		title: `${status}: ${error.message}`
	}
};
	}
</script>

<script>
	export let title;
</script>

<h1>{title}</h1>

Server-side stack traces will be removed from error in production, to avoid exposing privileged information to users.

Loading permalink

A component that defines a page or a layout can export a load function that runs before the component is created. This function runs both during server-side rendering and in the client, and allows you to get data for a page without (for example) showing a loading spinner and fetching data in onMount.

// load TypeScript type definitions

type LoadInput<
	PageParams extends Record<string, string> = Record<string, string>,
	Context extends Record<string, any> = Record<string, any>,
	Session = any
> = {
	page: {
host: string;
path: string;
params: PageParams;
query: URLSearchParams;
	};
	fetch: (info: RequestInfo, init?: RequestInit) => Promise<Response>;
	session: Session;
	context: Context;
};

type LoadOutput<
	Props extends Record<string, any> = Record<string, any>,
	Context extends Record<string, any> = Record<string, any>
> = {
	status?: number;
	error?: string | Error;
	redirect?: string;
	props?: Props;
	context?: Context;
	maxage?: number;
};

Our example blog page might contain a load function like the following. Note the context="module" — this is necessary because load runs before the component is rendered:

<script context="module">
	/**
	 * @type {import('@sveltejs/kit').Load}
	 */
	export async function load({ page, fetch, session, context }) {
const url = `/blog/${page.params.slug}.json`;
const res = await fetch(url);

if (res.ok) {
	return {
		props: {
			article: await res.json()
		}
	};
}

return {
	status: res.status,
	error: new Error(`Could not load ${url}`)
};
	}
</script>

load is similar to getStaticProps or getServerSideProps in Next.js, except that it runs on both the server and the client.

If load returns nothing, SvelteKit will fall through to other routes until something responds, or will respond with a generic 404.

SvelteKit's load receives an implemention of fetch, which has the following special properties:

  • it has access to cookies on the server
  • it can make requests against the app's own endpoints without issuing an HTTP call
  • it makes a copy of the response when you use it, and then sends it embedded in the initial page load for hydration

load only applies to page and layout components (not components they import), and runs on both the server and in the browser with the default rendering options.

Code called inside load blocks:

  • should use the SvelteKit-provided fetch wrapper rather than using the native fetch
  • should not reference window, document, or any browser-specific objects
  • should not directly reference any API keys or secrets, which will be exposed to the client, but instead call an endpoint that uses any required secrets

It is recommended that you not store pre-request state in global variables, but instead use them only for cross-cutting concerns such as caching and holding database connections.

Mutating any shared state on the server will affect all clients, not just the current one.

Input

The load function receives an object containing four fields — page, fetch, session and context. The load function is reactive, and will re-run when its parameters change, but only if they are used in the function. Specifically, if page.query, page.path, session, or context are used in the function, they will be re-run whenever their value changes. Note that destructuring parameters in the function declaration is enough to count as using them. In the example above, the load({ page, fetch, session, context }) function will re-run every time session or context is changed, even though they are not used in the body of the function. If it was re-written as load({ page, fetch }), then it would only re-run when page.params.slug changes. The same reactivity applies to page.params, but only to the params actually used in the function. If page.params.foo changes, the example above would not re-run, because it did not access page.params.foo, only page.params.slug.

page

page is a { host, path, params, query } object where host is the URL's host, path is its pathname, params is derived from path and the route filename, and query is an instance of URLSearchParams.

So if the example above was src/routes/blog/[slug].svelte and the URL was https://example.com/blog/some-post?foo=bar&baz&bizz=a&bizz=b, the following would be true:

  • page.host === 'example.com'
  • page.path === '/blog/some-post'
  • page.params.slug === 'some-post'
  • page.query.get('foo') === 'bar'
  • page.query.has('baz')
  • page.query.getAll('bizz') === ['a', 'b']

fetch

fetch is equivalent to the native fetch web API, and can make credentialed requests. It can be used across both client and server contexts.

When fetch runs on the server, the resulting response will be serialized and inlined into the rendered HTML. This allows the subsequent client-side load to access identical data immediately without an additional network request.

Cookies will only be passed through if the target host is the same as the SvelteKit application or a more specific subdomain of it.

session

session can be used to pass data from the server related to the current request, e.g. the current user. By default it is undefined. See getSession to learn how to use it.

context

context is passed from layout components to child layouts and page components. For the root __layout.svelte component, it is equal to {}, but if that component's load function returns an object with a context property, it will be available to subsequent load functions.

Output

If you return a Promise from load, SvelteKit will delay rendering until the promise resolves. The return value has several properties, all optional:

status

The HTTP status code for the page. If returning an error this must be a 4xx or 5xx response; if returning a redirect it must be a 3xx response. The default is 200.

error

If something goes wrong during load, return an Error object or a string describing the error alongside a 4xx or 5xx status code.

redirect

If the page should redirect (because the page is deprecated, or the user needs to be logged in, or whatever else) return a string containing the location to which they should be redirected alongside a 3xx status code.

maxage

To cause pages to be cached, return a number describing the page's max age in seconds. The resulting cache header will include private if user data was involved in rendering the page (either via session, or because a credentialed fetch was made in a load function), but otherwise will include public so that it can be cached by CDNs.

This only applies to page components, not layout components.

props

If the load function returns a props object, the props will be passed to the component when it is rendered.

context

This will be merged with any existing context and passed to the load functions of subsequent layout and page components.

This only applies to layout components, not page components.

Hooks permalink

An optional src/hooks.js (or src/hooks.ts, or src/hooks/index.js) file exports three functions, all optional, that run on the server — handle, getSession, and serverFetch.

The location of this file can be configured as config.kit.files.hooks

handle

This function runs on every request, for both pages and endpoints, and determines the response. It receives the request object and a function called resolve, which invokes SvelteKit's router and generates a response accordingly. This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing endpoints programmatically, for example).

If unimplemented, defaults to ({ request, resolve }) => resolve(request).

// handle TypeScript type definitions

type Headers = Record<string, string>;

type Request<Locals = Record<string, any>> = {
	method: string;
	host: string;
	headers: Headers;
	path: string;
	params: Record<string, string>;
	query: URLSearchParams;
	rawBody: string | Uint8Array;
	body: ParameterizedBody<Body>;
	locals: Locals; // populated by hooks handle
};

type Response = {
	status: number;
	headers: Headers;
	body?: string | Uint8Array;
};

type Handle<Locals = Record<string, any>> = (input: {
	request: Request<Locals>;
	resolve: (request: Request<Locals>) => Response | Promise<Response>;
}) => Response | Promise<Response>;

To add custom data to the request, which is passed to endpoints, populate the request.locals object, as shown below.

/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ request, resolve }) {
	request.locals.user = await getUserInformation(request.headers.cookie);

	const response = await resolve(request);

	return {
...response,
headers: {
	...response.headers,
	'x-custom-header': 'potato'
}
	};
}

getSession

This function takes the request object and returns a session object that is accessible on the client and therefore must be safe to expose to users. It runs whenever SvelteKit server-renders a page.

If unimplemented, session is {}.

// getSession TypeScript type definition

type GetSession<Locals = Record<string, any>, Session = any> = {
	(request: Request<Locals>): Session | Promise<Session>;
};
/** @type {import('@sveltejs/kit').GetSession} */
export function getSession(request) {
	return request.locals.user ? {
user: {
	// only include properties needed client-side —
	// exclude anything else attached to the user
	// like access tokens etc
	name: request.locals.user.name,
	email: request.locals.user.email,
	avatar: request.locals.user.avatar
}
	} : {};
}

session must be serializable, which means it must not contain things like functions or custom classes, just built-in JavaScript data types

serverFetch

This function allows you to modify (or replace) a fetch request for an external resource that happens inside a load function that runs on the server (or during pre-rendering).

For example, your load function might make a request to a public URL like https://api.yourapp.com when the user performs a client-side navigation to the respective page, but during SSR it might make sense to hit the API directly (bypassing whatever proxies and load balancers sit between it and the public internet).

type ServerFetch = (req: Request) => Promise<Response>;
/** @type {import('@sveltejs/kit').ServerFetch} */
export async function serverFetch(request) {
	if (request.url.startsWith('https://api.yourapp.com/')) {
// clone the original request, but change the URL
request = new Request(
	request.url.replace('https://api.yourapp.com/', 'http://localhost:9999/'),
	request
);
	}

	return fetch(request);
}

Modules permalink

SvelteKit makes a number of modules available to your application.

$app/env

import { amp, browser, dev, mode, prerendering } from '$app/env';
  • amp is true or false depending on the corresponding value in your project configuration
  • browser is true or false depending on whether the app is running in the browser or on the server
  • dev is true in development mode, false in production
  • mode is the Vite mode, which is development in dev mode or production during build unless configured otherwise in config.kit.vite.mode.
  • prerendering is true when prerendering, false otherwise

$app/navigation

import { goto, invalidate, prefetch, prefetchRoutes } from '$app/navigation';
  • goto(href, { replaceState, noscroll, keepfocus, state }) returns a Promise that resolves when SvelteKit navigates (or fails to navigate, in which case the promise rejects) to the specified href. The second argument is optional:
    • replaceState (boolean, default false) If true, will replace the current history entry rather than creating a new one with pushState
    • noscroll (boolean, default false) If true, the browser will maintain its scroll position rather than scrolling to the top of the page after navigation
    • keepfocus (boolean, default false) If true, the currently focused element will retain focus after navigation. Otherwise, focus will be reset to the body
    • state (object, default {}) The state of the new/updated history entry
  • invalidate(href) causes any load functions belonging to the currently active page to re-run if they fetch the resource in question. It returns a Promise that resolves when the page is subsequently updated.
  • prefetch(href) programmatically prefetches the given page, which means a) ensuring that the code for the page is loaded, and b) calling the page's load function with the appropriate options. This is the same behaviour that SvelteKit triggers when the user taps or mouses over an <a> element with sveltekit:prefetch. If the next navigation is to href, the values returned from load will be used, making navigation instantaneous. Returns a Promise that resolves when the prefetch is complete.
  • prefetchRoutes(routes) — programmatically prefetches the code for routes that haven't yet been fetched. Typically, you might call this to speed up subsequent navigation. If no argument is given, all routes will be fetched; otherwise, you can specify routes by any matching pathname such as /about (to match src/routes/about.svelte) or /blog/* (to match src/routes/blog/[slug].svelte). Unlike prefetch, this won't call load for individual pages. Returns a Promise that resolves when the routes have been prefetched.

$app/paths

import { base, assets } from '$app/paths';
  • base — a root-relative (i.e. begins with a /) string that matches config.kit.paths.base in your project configuration
  • assets — a root-relative or absolute path that matches config.kit.paths.assets (after it has been resolved against base)

$app/stores

import { getStores, navigating, page, session } from '$app/stores';

Stores are contextual — they are added to the context of your root component. This means that session and page are unique to each request on the server, rather than shared between multiple requests handled by the same server simultaneously, which is what makes it safe to include user-specific data in session.

Because of that, the stores are not free-floating objects: they must be accessed during component initialisation, like anything else that would be accessed with getContext.

  • getStores is a convenience function around getContext that returns { navigating, page, session }. This needs to be called at the top-level or synchronously during component or page initialisation.

The stores themselves attach to the correct context at the point of subscription, which means you can import and use them directly in components without boilerplate. However, it still needs to be called synchronously on component or page initialisation when $-prefix isn't used. Use getStores to safely .subscribe asynchronously instead.

  • navigating is a readable store. When navigating starts, its value is { from, to }, where from and to both mirror the page store value. When navigating finishes, its value reverts to null.
  • page is a readable store whose value reflects the object passed to load functions — it contains host, path, params and query. See the page section above for more details.
  • session is a writable store whose initial value is whatever was returned from getSession. It can be written to, but this will not cause changes to persist on the server — this is something you must implement yourself.

$lib

This is a simple alias to src/lib, or whatever directory is specified as [config.kit.files.lib]. It allows you to access common components and utility modules without ../../../../ nonsense.

$service-worker

This module is only available to service workers.

import { build, files, timestamp } from '$service-worker';
  • build is an array of URL strings representing the files generated by Vite, suitable for caching with cache.addAll(build)
  • files is an array of URL strings representing the files in your static directory, or whatever directory is specified by config.kit.files.assets. You can exclude certain files from static directory using config.kit.serviceWorker.exclude
  • timestamp is the result of calling Date.now() at build time. It's useful for generating unique cache names inside your service worker, so that a later deployment of your app can invalidate old caches

Service workers permalink

Service workers act as proxy servers that handle network requests inside your app. This makes it possible to make your app work offline, but even if you don't need offline support (or can't realistically implement it because of the type of app you're building), it's often worth using service workers to speed up navigation by precaching your built JS and CSS.

In SvelteKit, if you have a src/service-worker.js file (or src/service-worker.ts, or src/service-worker/index.js, etc) it will be built with Vite and automatically registered.

You can change the location of your service worker in your project configuration.

Inside the service worker you have access to the $service-worker module.

Because it needs to be bundled (since browsers don't yet support import in this context), and depends on the client-side app's build manifest, service workers only work in the production build, not in development. To test it locally, use svelte-kit preview.

Anchor options permalink

sveltekit:prefetch

SvelteKit uses code splitting to break your app into small chunks (one per route), ensuring fast startup times.

For dynamic routes, such as our src/routes/blog/[slug].svelte example, that's not enough. In order to render the blog post, we need to fetch the data for it, and we can't do that until we know what slug is. In the worst case, that could cause lag as the browser waits for the data to come back from the server.

We can mitigate that by prefetching the data. Adding a sveltekit:prefetch attribute to a link...

<a sveltekit:prefetch href="blog/what-is-sveltekit">What is SvelteKit?</a>

...will cause SvelteKit to run the page's load function as soon as the user hovers over the link (on a desktop) or touches it (on mobile), rather than waiting for the click event to trigger navigation. Typically, this buys us an extra couple of hundred milliseconds, which is the difference between a user interface that feels laggy, and one that feels snappy.

Note that prefetching will not work if the router setting is false.

You can also programmatically invoke prefetch from $app/navigation.

sveltekit:noscroll

When navigating to internal links, SvelteKit mirrors the browser's default navigation behaviour: it will change the scroll position to 0,0 so that the user is at the very top left of the page (unless the link includes a #hash, in which case it will scroll to the element with a matching ID).

In certain cases, you may wish to disable this behaviour. Adding a sveltekit:noscroll attribute to a link...

<a href="path" sveltekit:noscroll>Path</a>

...will prevent scrolling after the link is clicked.

rel=external

By default, the SvelteKit runtime intercepts clicks on <a> elements and bypasses the normal browser navigation for relative (same-origin) URLs that match one of your page routes. We sometimes need to tell SvelteKit that certain links need to be handled by normal browser navigation.

Adding a rel=external attribute to a link...

<a rel="external" href="path">Path</a>

...will trigger a browser navigation when the link is clicked.

Events permalink

SvelteKit emits CustomEvents on the window object when certain things happen:

  • sveltekit:start — fired once the app has hydrated
  • sveltekit:navigation-start — navigation has started
  • sveltekit:navigation-end — navigation has ended

You probably won't need to use these, but they can be useful in the context of (for example) integration tests.

AMP permalink

An unfortunate reality of modern web development is that it is sometimes necessary to create an AMP version of your site. In SvelteKit this can be done by setting the amp config option, which has the following effects:

  • Client-side JavaScript, including the router, is disabled
  • Styles are concatenated into <style amp-custom>, and the AMP boilerplate is injected
  • In development, requests are checked against the AMP validator so you get early warning of any errors

Adapters permalink

Before you can deploy your SvelteKit app, you need to adapt it for your deployment target. Adapters are small plugins that take the built app as input and generate output for deployment. Many adapters are optimised for a specific hosting provider, and you can generally find information about deployment in your adapter's documentation. However, some adapters, like adapter-static, build output that can be hosted on numerous hosting providers, so it may also be helpful to reference the documentation of your hosting provider in these cases.

For example, if you want to run your app as a simple Node server, you would use the @sveltejs/adapter-node@next package:

// svelte.config.js
import node from '@sveltejs/adapter-node';

export default {
	kit: {
adapter: node()
	}
};

With this, svelte-kit build will generate a self-contained Node app inside build. You can pass options to adapters, such as customising the output directory in adapter-node:

// svelte.config.js
import node from '@sveltejs/adapter-node';

export default {
	kit: {
-		adapter: node()
+		adapter: node({ out: 'my-output-directory' })
	}
};

A variety of official adapters exist for serverless platforms...

...and traditional platforms:

  • adapter-node — for creating self-contained Node apps
  • adapter-static — for prerendering your entire site as a collection of static files

As well as community-provided adapters. You may also write your own adapter.

SSR and JavaScript permalink

By default, SvelteKit will render any component first on the server and send it to the client as HTML. It will then render the component again in the browser to make it interactive in a process called hydration. For this reason, you need to ensure that components can run in both places. SvelteKit will then initialise a router that takes over subsequent navigations.

You can control each of these on a per-app or per-page basis. Note that each of the per-page settings use context="module", and only apply to page components, not layout components.

If both are specified, per-page settings override per-app settings in case of conflicts. Each setting can be controlled independently, but ssr and hydrate cannot both be false since that would result in nothing being rendered at all.

ssr

Disabling server-side rendering effectively turns your SvelteKit app into a single-page app or SPA.

In most situations this is not recommended: see the discussion in the appendix. Consider whether it's truly appropriate to disable and don't simply disable SSR because you've hit an issue with it.

You can disable SSR app-wide with the ssr config option, or a page-level ssr export:

<script context="module">
	export const ssr = false;
</script>

router

SvelteKit includes a client-side router that intercepts navigations (from the user clicking on links, or interacting with the back/forward buttons) and updates the page contents, rather than letting the browser handle the navigation by reloading.

In certain circumstances you might need to disable client-side routing with the app-wide router config option or the page-level router export:

<script context="module">
	export const router = false;
</script>

Note that this will disable client-side routing for any navigation from this page, regardless of whether the router is already active.

hydrate

Ordinarily, SvelteKit hydrates your server-rendered HTML into an interactive page. Some pages don't require JavaScript at all — many blog posts and 'about' pages fall into this category. In these cases you can skip hydration when the app boots up with the app-wide hydrate config option or the page-level hydrate export:

<script context="module">
	export const hydrate = false;
</script>

If hydrate and router are both false, SvelteKit will not add any JavaScript to the page at all.

prerender

It's likely that at least some pages of your app can be represented as a simple HTML file generated at build time. These pages can be prerendered by your adapter.

If your entire app is suitable for prerendering, you could use adapter-static, which will generate HTML files for every page, plus additional files that are requested by load functions in those pages.

In many cases, you'll only want to prerender specific pages in your app. You'll need to annotate these pages:

<script context="module">
	export const prerender = true;
</script>

The prerenderer will start at the root of your app and generate HTML for any prerenderable pages it finds. Each page is scanned for <a> elements that point to other pages that are candidates for prerendering — because of this, you generally don't need to specify which pages should be accessed. If you do need to specify which pages should be accessed by the prerenderer, you can do so with the pages option in the prerender configuration.

When not to prerender

The basic rule is this: for a page to be prerenderable, any two users hitting it directly must get the same content from the server.

Not all pages are suitable for prerendering. Any content that is prerendered will be seen by all users. You can of course fetch personalized data in onMount in a prerendered page, but this may result in a poorer user experience since it will involve blank initial content or loading indicators.

Note that you can still prerender pages that load data based on the page's parameters, like our src/routes/blog/[slug].svelte example from earlier. The prerenderer will intercept requests made inside load, so the data served from src/routes/blog/[slug].json.js will also be captured.

Route conflicts

Because prerendering writes to the filesystem, it isn't possible to have two endpoints that would cause a directory and a file to have the same name. For example, src/routes/foo/index.js and src/routes/foo/bar.js would try to create foo and foo/bar, which is impossible.

For that reason among others, it's recommended that you always include a file extension — src/routes/foo/index.json.js and src/routes/foo/bar.json.js would result in foo.json and foo/bar.json files living harmoniously side-by-side.

For pages, we skirt around this problem by writing foo/index.html instead of foo.

Packaging permalink

You can use SvelteKit to build component libraries as well as apps.

When you're creating an app, the contents of src/routes is the public-facing stuff; src/lib contains your app's internal library.

A SvelteKit component library has the exact same structure as a SvelteKit app, except that src/lib is the public-facing bit. src/routes might be a documentation or demo site that accompanies the library, or it might just be a sandbox you use during development.

Running svelte-kit package will take the contents of src/lib and generate a package directory (which can be configured) containing the following:

  • All the files in src/lib, unless you configure custom include/exclude options. Svelte components will be preprocessed, TypeScript files will be transpiled to JavaScript.
  • Type definitions (d.ts files) which are generated for Svelte, JavaScript and TypeScript files. You need to install typescript >= 4.0.0 and svelte2tsx >= 0.4.1 for this. Type definitions are placed next to their implementation, hand-written d.ts files are copied over as is. You can disable generation, but we strongly recommend against it.
  • A package.json copied from the project root without the "scripts" field and adds a "type": "module". An "exports" field will also be added if it's not defined in the original file.

The "exports" field contains the package's entry points. By default, all files in src/lib will be treated as an entry point unless they start with (or live in a directory that starts with) an underscore, but you can configure this behaviour. If you have a src/lib/index.js or src/lib/index.svelte file, it will be treated as the package root.

For example, if you had a src/lib/Foo.svelte component and a src/lib/index.js module that re-exported it, a consumer of your library could do either of the following:

import { Foo } from 'your-library';
import Foo from 'your-library/Foo.svelte';

Publishing

To publish the generated package:

npm publish package

The package above is referring to the directory name generated, change accordingly if you configure a custom package.dir. If you're having problems publishing a package that is not yours, add a trailing slash at the end (e.g. package/).

Caveats

This is a relatively experimental feature and is not yet fully implemented. All files except Svelte files (preprocessed) and TypeScript files (transpiled to JavaScript) are copied across as-is.

Command Line Interface permalink

SvelteKit includes a command line interface for building and running your app.

In the default project template svelte-kit dev, svelte-kit build and svelte-kit preview are aliased as npm run dev, npm run build and npm run preview respectively. You can also invoke the CLI with npx:

npx svelte-kit dev

svelte-kit dev

Starts a development server. It accepts the following options:

  • -p/--port — which port to start the server on
  • -o/--open — open a browser tab once the server starts
  • -h/--host — expose the server to the network. This will allow people using the same coffee shop WiFi as you to see files on your computer due to an issue in Vite; use it with care
  • -H/--https — launch an HTTPS server using a self-signed certificate. Useful for testing HTTPS-only features on an external device

svelte-kit build

Builds a production version of your app, and runs your adapter if you have one specified in your config. It accepts the following option:

  • --verbose — log more detail

After building the app, you can reference the documentation of your chosen adapter and hosting platform for specific instructions on how to serve your app.

svelte-kit preview

After you've built your app with svelte-kit build, you can start the production version (irrespective of any adapter that has been applied) locally with svelte-kit preview. This is intended for testing the production build locally, not for serving your app, for which you should always use an adapter.

Like svelte-kit dev, it accepts the following options:

  • -p/--port
  • -o/--open
  • -h/--host (note the security caveat above)
  • -H/--https

svelte-kit package

For package authors, see packaging.

Configuration permalink

Your project's configuration lives in a svelte.config.js file. All values are optional. The complete list of options, with defaults, is shown here:

/** @type {import('@sveltejs/kit').Config} */
const config = {
	// options passed to svelte.compile (https://svelte.dev/docs#svelte_compile)
	compilerOptions: null,

	// an array of file extensions that should be treated as Svelte components
	extensions: ['.svelte'],

	kit: {
adapter: null,
amp: false,
appDir: '_app',
files: {
	assets: 'static',
	hooks: 'src/hooks',
	lib: 'src/lib',
	routes: 'src/routes',
	serviceWorker: 'src/service-worker',
	template: 'src/app.html'
},
floc: false,
host: null,
hostHeader: null,
hydrate: true,
package: {
	dir: 'package',
	emitTypes: true,
	exports: {
		include: ['**'],
		exclude: ['_*', '**/_*']
	},
	files: {
		include: ['**'],
		exclude: []
	}
},
paths: {
	assets: '',
	base: ''
},
prerender: {
	crawl: true,
	enabled: true,
	onError: 'fail',
	pages: ['*']
},
router: true,
serviceWorker: {
	exclude: []
},
ssr: true,
target: null,
trailingSlash: 'never',
vite: () => ({})
	},

	// options passed to svelte.preprocess (https://svelte.dev/docs#svelte_preprocess)
	preprocess: null
};

export default config;

adapter

Determines how the output of svelte-kit build is converted for different platforms. See Adapters.

amp

Enable AMP mode.

appDir

The directory relative to paths.assets where the built JS and CSS (and imported assets) are served from. (The filenames therein contain content-based hashes, meaning they can be cached indefinitely). Must not start or end with /.

files

An object containing zero or more of the following string values:

  • assets — a place to put static files that should have stable URLs and undergo no processing, such as favicon.ico or manifest.json
  • hooks — the location of your hooks module (see Hooks)
  • lib — your app's internal library, accessible throughout the codebase as $lib
  • routes — the files that define the structure of your app (see Routing)
  • serviceWorker — the location of your service worker's entry point (see Service workers)
  • template — the location of the template for HTML responses

floc

Google's FLoC is a technology for targeted advertising that the Electronic Frontier Foundation has deemed harmful to user privacy. Browsers other than Chrome have declined to implement it.

In common with services like GitHub Pages, SvelteKit protects your users by automatically opting out of FLoC. It adds the following header to responses unless floc is true:

Permissions-Policy: interest-cohort=()

This only applies to server-rendered responses — headers for prerendered pages (e.g. created with adapter-static) are determined by the hosting platform.

host

A value that overrides the Host header when populating page.host

hostHeader

If your app is behind a reverse proxy (think load balancers and CDNs) then the Host header will be incorrect. In most cases, the underlying host is exposed via the X-Forwarded-Host header and you should specify this in your config if you need to access page.host:

// svelte.config.js
export default {
	kit: {
hostHeader: 'X-Forwarded-Host'
	}
};

You should only do this if you trust the reverse proxy, which is why it isn't the default.

hydrate

Whether to hydrate the server-rendered HTML with a client-side app. (It's rare that you would set this to false on an app-wide basis.)

package

Options related to creating a package.

  • dir - output directory
  • emitTypes - by default, svelte-kit package will automatically generate types for your package in the form of d.ts. files. While generating types is configurable, we believe it is best for the ecosystem quality to generate types, always. Please make sure you have a good reason when setting it to false (for example when you want to provide handwritten type definitions instead).
  • exports - contains a includes and a excludes array which specifies which files to mark as exported from the exports field of the package.json
  • files - contains a includes and a excludes array which specifies which files to process and copy over when packaging

paths

An object containing zero or more of the following string values:

  • assets — an absolute path, or a path relative to base, where your app's files are served from. This is useful if your files are served from a storage bucket of some kind
  • base — a root-relative path that must start, but not end with / (e.g. /base-path). This specifies where your app is served from and allows the app to live on a non-root path

prerender

See Prerendering. An object containing zero or more of the following:

  • crawl — determines whether SvelteKit should find pages to prerender by following links from the seed page(s)

  • enabled — set to false to disable prerendering altogether

  • onError

    • 'fail' — (default) fails the build when a routing error is encountered when following a link

    • 'continue' — allows the build to continue, despite routing errors

    • function — custom error handler allowing you to log, throw and fail the build, or take other action of your choosing based on the details of the crawl

      /** @type {import('@sveltejs/kit').PrerenderErrorHandler} */
      const handleError = ({ status, path, referrer, referenceType }) => {
      	if (path.startsWith('/blog')) throw new Error('Missing a blog page!');
      	console.warn(`${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}`);
      };
      
      export default {
      	kit: {
      adapter: static(),
      target: '#svelte',
      prerender: {
      	onError: handleError
      }
      	}
      };
  • pages — an array of pages to prerender, or start crawling from (if crawl: true). The * string includes all non-dynamic routes (i.e. pages with no [parameters] )

router

Enables or disables the client-side router app-wide.

serviceWorker

An object containing zero or more of the following values:

  • exclude - an array of glob patterns relative to files.assets dir. Files matching any of these would not be available in $service-worker.files e.g. if files.assets has value static then ['og-tags-images/**/*'] would match all files under static/og-tags-images dir.

ssr

Enables or disables server-side rendering app-wide.

target

Specifies an element to mount the app to. It must be a DOM selector that identifies an element that exists in your template file. If unspecified, the app will be mounted to document.body.

trailingSlash

Whether to remove, append, or ignore trailing slashes when resolving URLs to routes.

  • "never" — redirect /x/ to /x
  • "always" — redirect /x to /x/
  • "ignore" — don't automatically add or remove trailing slashes. /x and /x/ will be treated equivalently

Ignoring trailing slashes is not recommended — the semantics of relative paths differ between the two cases (./y from /x is /y, but from /x/ is /x/y), and /x and /x/ are treated as separate URLs which is harmful to SEO. If you use this option, ensure that you implement logic for conditionally adding or removing trailing slashes from request.path inside your handle function.

vite

A Vite config object, or a function that returns one. Not all configuration options can be set, since SvelteKit depends on certain values being configured internally.

Writing an Adapter permalink

We recommend looking at the source for an adapter to a platform similar to yours and copying it as a starting point.

Adapters packages must implement the following API, which creates an Adapter:

/**
 * @param {AdapterSpecificOptions} options
 */
export default function (options) {
	/** @type {import('@sveltejs/kit').Adapter} */
	return {
name: 'adapter-package-name',
async adapt({ utils, config }) {
	// adapter implementation
}
	};
}

The types for Adapter and its parameters are available in types/config.d.ts.

Within the adapt method, there are a number of things that an adapter should do:

  • Clear out the build directory
  • Output code that:
    • Calls init
    • Converts from the platform's request to a SvelteKit request, calls render, and converts from a SvelteKit response to the platform's
    • Globally shims fetch to work on the target platform. SvelteKit provides a @sveltejs/kit/install-fetch helper for platforms that can use node-fetch
  • Bundle the output to avoid needing to install dependencies on the target platform, if desired
  • Call utils.prerender
  • Put the user's static files and the generated JS/CSS in the correct location for the target platform

If possible, we recommend putting the adapter output under the build/ directory with any intermediate output placed under '.svelte-kit/' + adapterName.

The adapter API may change before 1.0.

Troubleshooting permalink

FAQ

Please see the FAQ for solutions to common issues and helpful tips and tricks.

Support

You can ask for help on Discord and StackOverflow. Please first search for information related to your issue in the FAQ, Google or another search engine, issue tracker, and Discord chat history in order to be respectful of others' time. There are many more people asking questions than answering them, so this will help in allowing the community to grow in a scalable fashion.

Appendix permalink

The core of SvelteKit provides a highly configurable rendering engine. This section describes some of the terms used when discussing rendering. A reference for setting these options is provided in the documentation above.

SSR

Server-side rendering (SSR) is the generation of the page contents on the server. SSR is generally preferred for SEO. While some search engines can index content that is dynamically generated on the client-side it may take longer even in these cases. It also tends to improve perceived performance and makes your app accessible to users if JavaScript fails or is disabled (which happens more often than you probably think).

CSR and SPA

Client-side rendering (CSR) is the generation of the page contents in the web browser using JavaScript. A single-page app (SPA) is an application in which all requests to the server load a single HTML file which then does client-side rendering of the requested contents based on the requested URL. All navigation is handled on the client-side in a process called client-side routing with per-page contents being updated and common layout elements remaining largely unchanged. SPAs do not provide SSR, which has the shortcoming described above. However, some applications are not greatly impacted by these shortcomings such as a complex business application behind a login where SEO would not be important and it is known that users will be accessing the application from a consistent computing environment.

Prerendering

Prerendering means computing the contents of a page at build time and saving the HTML for display. This approach has the same benefits as traditional server-rendered pages, but avoids recomputing the page for each visitor and so scales nearly for free as the number of visitors increases. The tradeoff is that the build process is more expensive and prerendered content can only be updated by building and deploying a new version of the application.

Not all pages can be prerendered. The basic rule is this: for content to be prerenderable, any two users hitting it directly must get the same content from the server. Note that you can still prerender content that is loaded based on the page's parameters as long as all users will be seeing the same prerendered content.

Pre-rendered pages are not limited to static content. You can build personalized pages if user-specific data is fetched and rendered client-side. This is subject to the caveat that you will experience the downsides of not doing SSR for that content as discussed above.

SSG

Static Site Generation (SSG) is a term that refers to a site where every page is prerendered. This is what SvelteKit's adapter-static does. SvelteKit was not built to do only static site generation like some tools and so may not scale as well to efficiently render a very large number of pages as tools built specifically for that purpose. However, in contrast to most purpose-built SSGs, SvelteKit does nicely allow for mixing and matching different rendering types on different pages. One benefit of fully prerendering a site is that you do not need to maintain or pay for servers to perform SSR. Once generated, the site can be served from CDNs, leading to great "time to first byte" performance. This delivery model is often referred to as JAMstack.

Hydration

Svelte components store some state and update the DOM when the state is updated. When fetching data during SSR, by default SvelteKit will store this data and transmit it to the client along with the server-rendered HTML. The components can then be initialized on the client with that data without having to call the same API endpoints again. Svelte will then check that the DOM is in the expected state and attach event listeners in a process called hydration. Once the components are fully hydrated, they can react to changes to their properties just like any newly created Svelte component.

Routing

By default, when you navigate to a new page (by clicking on a link or using the browser's forward or back buttons), SvelteKit will intercept the attempted navigation and handle it instead of allowing the browser to send a request to the server for the destination page. SvelteKit will then update the displayed contents on the client by rendering the component for the new page, which in turn can make calls to the necessary API endpoints. This process of updating the page on the client in response to attempted navigation is called client-side routing.