Introduction
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
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 behavior 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.
Endpoints
Endpoints are modules written in .js
(or .ts
) files that export functions corresponding to HTTP methods. 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:
type Request<Context = any> = {
host: string;
method: 'GET';
headers: Record<string, string>;
path: string;
params: Record<string, string | string[]>;
query: URLSearchParams;
body: string | Buffer | ReadOnlyFormData;
context: Context; // see getContext, below
};
type Response = {
status?: number;
headers?: Record<string, string>;
body?: any;
};
type RequestHandler<Context = any> = {
(request: Request<Context>) => Response | Promise<Response>;
}
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
}
};
}
}
Returning nothing is equivalent to an explicit 404 response.
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 is200
)3xx
— redirection (should be accompanied by alocation
header)4xx
— client error5xx
— 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.)
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'shttp
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.The
body
property of the request object exists in the case of POST requests. If you're posting form data, it will be a read-only version of theFormData
object.
To set multiple cookies in a single set of response headers, you can return an array:
return {
headers: {
'set-cookie': [cookie1, cookie2]
}
};
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
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. 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>
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 recommend 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
A component that defines a page 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
.
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:
type LoadInput = {
page: {
host: string;
path: string;
params: Record<string, string | string[]>;
query: URLSearchParams;
};
fetch: (info: RequestInfo, init?: RequestInit) => Promise<Response>;
session: any;
context: Record<string, any>;
};
type LoadOutput = {
status?: number;
error?: Error;
redirect?: string;
props?: Record<string, any>;
context?: Record<string, any>;
maxage?: number;
};
<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.
load
only applies to components that define pages, not the components that they import.
Input
The load
function receives an object containing four fields — page
, fetch
, session
and context
.
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 /blog/some-post?foo=bar&baz&bizz=a&bizz=b
, the following would be true:
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 credentialled 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-sideload
to access identical data immediately without an additional network request.
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.
It is important to note that
load
may run on either the server or in the client browser. Code called insideload
blocks:
- should run on the same domain as any upstream API servers requiring credentials
- should not reference
window
,document
or any browser-specific objects- should not reference any API keys or secrets, which will be exposed to the client
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 credentialled 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
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 — getContext, getSession and handle.
The location of this file can be configured as
config.kit.files.hooks
getContext
This function runs on every incoming request. It generates the context
object that is available to endpoint handlers as request.context
, and used to derive the session
object available in the browser.
If unimplemented, context is {}
.
type Incoming = {
method: string;
host: string;
headers: Headers;
path: string;
query: URLSearchParams;
body: string | Buffer | ReadOnlyFormData;
};
type GetContext<Context = any> = {
(incoming: Incoming): Context;
};
import * as cookie from 'cookie';
import db from '$lib/db';
/** @type {import('@sveltejs/kit').GetContext} */
export async function getContext({ headers }) {
const cookies = cookie.parse(headers.cookie || '');
return {
user: (await db.get_user(cookies.session_id)) || { guest: true }
};
}
getSession
This function takes the context
object and returns a session
object that is safe to expose to the browser. It runs whenever SvelteKit renders a page.
If unimplemented, session is {}
.
type GetSession<Context = any, Session = any> = {
({ context }: { context: Context }): Session | Promise<Session>;
};
/** @type {import('@sveltejs/kit').GetSession} */
export function getSession({ context }) {
return {
user: {
// only include properties needed client-side —
// exclude anything else attached to the user
// like access tokens etc
name: context.user?.name,
email: context.user?.email,
avatar: context.user?.avatar
}
};
}
session
must be serializable, which means it must not contain things like functions or custom classes, just built-in JavaScript data types
handle
This function runs on every request, and determines the response. It receives the request
object and render
method, which calls SvelteKit's default renderer. This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing endpoints programmatically, for example).
If unimplemented, defaults to ({ request, render }) => render(request)
.
type Request<Context = any> = {
method: string;
host: string;
headers: Headers;
path: string;
params: Record<string, string>;
query: URLSearchParams;
body: string | Buffer | ReadOnlyFormData;
context: Context;
};
type Response = {
status?: number;
headers?: Headers;
body?: any;
};
type Handle<Context = any> = ({
request: Request<Context>,
render: (request: Request<Context>) => Promise<Response>
}) => Response | Promise<Response>;
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ request, render }) {
const response = await render(request);
return {
...response,
headers: {
...response.headers,
'x-custom-header': 'potato'
}
};
}
Modules
SvelteKit makes a number of modules available to your application.
$app/env
import { amp, browser, dev, prerendering } from '$app/env';
amp
istrue
orfalse
depending on the corresponding value in your project configurationbrowser
istrue
orfalse
depending on whether the app is running in the browser or on the serverdev
istrue
in development mode,false
in productionprerendering
istrue
when prerendering,false
otherwise
$app/navigation
import { goto, prefetch, prefetchRoutes } from '$app/navigation';
goto(href, { replaceState, noscroll })
returns aPromise
that resolves when SvelteKit navigates (or fails to navigate, in which case the promise rejects) to the specifiedhref
. The second argument is optional. IfreplaceState
is true, a new history entry won't be created. Ifnoscroll
is true, the browser won't scroll to the top of the page after navigation.prefetch(href)
programmatically prefetches the given page, which means a) ensuring that the code for the page is loaded, and b) calling the page'sload
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 tohref
, the values returned fromload
will be used, making navigation instantaneous. Returns aPromise
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 matchsrc/routes/about.svelte
) or/blog/*
(to matchsrc/routes/blog/[slug].svelte
). Unlikeprefetch
, this won't callpreload
for individual pages. Returns aPromise
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 matchesconfig.kit.files.base
in your project configurationassets
— a root-relative or absolute path that matchesconfig.kit.files.assets
(after it has been resolved againstbase
)
$app/stores
import { getStores, navigating, page, session } from '$app/stores';
Stores are contextual — they are added to the context or 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 aroundgetContext
that returns{ navigating, page, session }
. Most of the time, you won't need to use it.
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.
navigating
is a readable store. When navigating starts, its value is{ from, to }
, wherefrom
andto
both mirror thepage
store value. When navigating finishes, its value reverts tonull
.page
is a readable store whose value reflects the object passed toload
functions — it containshost
,path
,params
andquery
. See thepage
section above for more details.session
is a writable store whose initial value is whatever was returned fromgetSession
. 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 withcache.addAll(build)
files
is an array of URL strings representing the files in yourstatic
directory, or whatever directory is specified byconfig.kit.files.assets
timestamp
is the result of callingDate.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
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 start
.
Anchor options
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
SvelteKit emits CustomEvents on the window
object when certain things happen:
sveltekit:start
— fired once the app has hydratedsveltekit:navigation-start
— navigation has startedsveltekit: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
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
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 that is optimised for a specific platform.
For example, if you want to run your app as a simple Node server, you would use the @sveltejs/adapter-node
package:
// svelte.config.cjs
const node = require('@sveltejs/adapter-node');
module.exports = {
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.cjs
const node = require('@sveltejs/adapter-node');
module.exports = {
kit: {
- adapter: node()
+ adapter: node({ out: 'my-output-directory' })
}
};
A variety of official adapters exist for serverless platforms...
adapter-begin
— for Beginadapter-cloudflare-workers
— for Cloudflare Workersadapter-netlify
— for Netlifyadapter-vercel
— for Vercel
...and others:
adapter-node
— for creating self-contained Node appsadapter-static
— for prerendering your entire site as a collection of static files
The adapter API is still in flux and will likely change before 1.0.
SSR and JavaScript
By default, SvelteKit will server-render pages on demand, then hydrate the rendered HTML in the client with an interactive Svelte app while initialising 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: 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). Sometimes it's appropriate or even necessary, but consider alternatives before disabling SSR.
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 this behaviour 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
androuter
are bothfalse
, 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, since they contain no dynamic or user-specific data. 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.
In other words, any app that involves user sessions or authentication is not a candidate for
adapter-static
, even if individual pages within an app are suitable for prerendering.
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
.
Command Line Interface
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 start
are aliased as npm run dev
, npm run build
and npm start
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; 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
svelte-kit start
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 start
. 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
Configuration
Your project's configuration lives in a svelte.config.cjs
file. All values are optional. The complete list of options, with defaults, is shown here:
/** @type {import('@sveltejs/kit').Config} */
module.exports = {
// 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'
},
host: null,
hostHeader: null,
hydrate: true,
paths: {
assets: '',
base: ''
},
prerender: {
crawl: true,
enabled: true,
force: false,
pages: ['*']
},
router: true,
ssr: true,
target: null,
vite: () => ({})
},
// options passed to svelte.preprocess (https://svelte.dev/docs#svelte_preprocess)
preprocess: null
};
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).
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 asfavicon.ico
ormanifest.json
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)hooks
— the location of your hooks module (see Hooks)template
— the location of the template for HTML responses
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.cjs
module.exports = {
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.)
paths
An object containing zero or more of the following string
values:
assets
— an absolute path, or a path relative tobase
, where your app's files are served from. This is useful if your files are served from a storage bucket of some kindbase
— a root-relative (i.e. starts with/
) path that specifies where your app is served from. This 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 tofalse
to disable prerendering altogetherforce
— iftrue
, a page that fails to render will not cause the entire build to failpages
— an array of pages to prerender, or start crawling from (ifcrawl: true
). The*
string includes all non-dynamic routes (i.e. pages with no[parameters]
)
router
Enables or disables the client-side router app-wide.
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
.
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.
Troubleshooting
Server-side rendering
SvelteKit will render any component first on the server side and send it to the client as HTML. It will then run the component again on the client side to allow it to update based on dynamic data. This means you need to ensure that components can run both on the client and server side.
If, for example, your components try to access the global variables document
or window
, this will result in an error when the page is pre-rendered on the server side.
If you need access to these variables, you can run code exclusively on the client side by wrapping it in
import { browser } from '$app/env';
if (browser) {
// client-only code here
}
Alternatively, you can run it onMount
, since this only runs in the browser. This is also a good way to load libraries that depend on window
:
<script>
import { onMount } from 'svelte';
let awkward;
onMount(async () => {
const module = await import('some-browser-only-library');
awkward = module.default;
});
</script>