Loading data
Edit this page on GitHubA +page.svelte
or +layout.svelte
gets its data
from a load
function.
If the load
function is defined in +page.js
or +layout.js
it will run both on the server and in the browser. If it's instead defined in +page.server.js
or +layout.server.js
it will only run on the server, in which case it can (for example) make database calls and access private environment variables, but can only return data that can be serialized with devalue. In both cases, the return value (if there is one) must be an object.
src/routes/+page.js
ts
/** @type {import('./$types').PageLoad} */export functionload (event ) {return {some : 'data'};}
src/routes/+page.ts
ts
import type {PageLoad } from './$types';export constload :PageLoad = (event ) => {return {some : 'data'};}
Input propertiespermalink
The argument to a load
function is a LoadEvent
(or, for server-only load
functions, a ServerLoadEvent
which inherits clientAddress
, cookies
, locals
, platform
and request
from RequestEvent
). All events have the following properties:
datapermalink
Very rarely, you might need both a +page.js
and a +page.server.js
(or the +layout
equivalent). In these cases, the data
for +page.svelte
comes from +page.js
, which in turn receives data
from the server:
src/routes/my-route/+page.server.js
ts
/** @type {import('./$types').PageServerLoad} */export functionload () {return {a : 1};}
src/routes/my-route/+page.server.ts
ts
import type {PageServerLoad } from './$types';export constload :PageServerLoad = () => {return {a : 1};}
src/routes/my-route/+page.js
ts
/** @type {import('./$types').PageLoad} */export functionload ({data }) {return {b :data .a * 2};}
src/routes/my-route/+page.ts
ts
import type {PageLoad } from './$types';export constload :PageLoad = ({data }) => {return {b :data .a * 2};}
src/routes/my-route/+page.svelte
<script>
/** @type {import('./$types').PageData} */ export let data;
console.log(data.a); // `undefined`, it wasn't passed through in +page.js
console.log(data.b); // `2`
</script>
src/routes/my-route/+page.svelte
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
console.log(data.a); // `undefined`, it wasn't passed through in +page.js
console.log(data.b); // `2`
</script>
In other words +page.server.js
passes data
along to +page.js
, which passes data
along to +page.svelte
.
paramspermalink
params
is derived from url.pathname
and the route filename.
For a route filename example like src/routes/a/[b]/[...c]
and a url.pathname
of /a/x/y/z
, the params
object would look like this:
{
"b": "x",
"c": "y/z"
}
routeIdpermalink
The name of the current route directory, relative to src/routes
:
src/routes/blog/[slug]/+page.js
ts
/** @type {import('./$types').PageLoad} */export functionload ({routeId }) {console .log (routeId ); // 'blog/[slug]'}
src/routes/blog/[slug]/+page.ts
ts
import type {PageLoad } from './$types';export constload :PageLoad = ({routeId }) => {console .log (routeId ); // 'blog/[slug]'}
urlpermalink
An instance of URL
, containing properties like the origin
, hostname
, pathname
and searchParams
(which contains the parsed query string as a URLSearchParams
object). url.hash
cannot be accessed during load
, since it is unavailable on the server.
In some environments this is derived from request headers during server-side rendering. If you're using adapter-node, for example, you may need to configure the adapter in order for the URL to be correct.
Input methodspermalink
LoadEvent
also has the following methods:
dependspermalink
This function declares that the load
function has a dependency on one or more URLs or custom identifiers, which can subsequently be used with invalidate()
to cause load
to rerun.
Most of the time you won't need this, as fetch
calls depends
on your behalf — it's only necessary if you're using a custom API client that bypasses fetch
.
URLs can be absolute or relative to the page being loaded, and must be encoded.
Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the URI specification.
The following example shows how to use depends
to register a dependency on the URLs to a custom API client as well as a custom identifier, which is invalidate
d after a button click, making the load
function rerun.
src/routes/+page.js
ts
import * asapi from '$lib/api';/** @type {import('./$types').PageLoad} */export async functionload ({depends }) {depends (`${api .base }/foo`,`${api .base }/bar`,'my-stuff:foo');return {foo :api .client .get ('/foo'),bar :api .client .get ('/bar')};}
src/routes/+page.ts
ts
import * asapi from '$lib/api';import type {PageLoad } from './$types';export constload :PageLoad = async ({depends }) => {depends (`${api .base }/foo`,`${api .base }/bar`,'my-stuff:foo');return {foo :api .client .get ('/foo'),bar :api .client .get ('/bar')};}
src/routes/+page.svelte
<script>
import { invalidate } from '$app/navigation';
/** @type {import('./$types').PageData} */ export let data;
const pageRefresh = async () => {
await invalidate('my-stuff:foo');
}
</script>
<p>{data.foo}<p>
<p>{data.bar}</p>
<button on:click={pageRefresh}>Refresh my stuff</button>
src/routes/+page.svelte
<script lang="ts">
import { invalidate } from '$app/navigation';
import type { PageData } from './$types';
export let data: PageData;
const pageRefresh = async () => {
await invalidate('my-stuff:foo');
}
</script>
<p>{data.foo}<p>
<p>{data.bar}</p>
<button on:click={pageRefresh}>Refresh my stuff</button>
fetchpermalink
fetch
is equivalent to the native fetch
web API, with a few additional features:
- it can be used to make credentialed requests on the server, as it inherits the
cookie
andauthorization
headers for the page request - it can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context) - internal requests (e.g. for
+server.js
routes) go direct to the handler function when running on the server, without the overhead of an HTTP call - during server-side rendering, the response will be captured and inlined into the rendered HTML. Note that headers will not be serialized, unless explicitly included via
filterSerializedResponseHeaders
- during hydration, the response will be read from the HTML, guaranteeing consistency and preventing 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.
parentpermalink
await parent()
returns data from parent layout load
functions. In +page.server.js
or +layout.server.js
it will return data from load
functions in parent +layout.server.js
files:
src/routes/+layout.server.js
ts
/** @type {import('./$types').LayoutServerLoad} */export functionload () {return {a : 1 };}
src/routes/+layout.server.ts
ts
import type {LayoutServerLoad } from './$types';export constload :LayoutServerLoad = () => {return {a : 1 };}
src/routes/foo/+layout.server.js
ts
/** @type {import('./$types').LayoutServerLoad} */export async functionload ({parent }) {const {a } = awaitparent ();console .log (a ); // `1`return {b : 2 };}
src/routes/foo/+layout.server.ts
ts
import type {LayoutServerLoad } from './$types';export constload :LayoutServerLoad = async ({parent }) => {const {a } = awaitparent ();console .log (a ); // `1`return {b : 2 };}
src/routes/foo/+page.server.js
ts
/** @type {import('./$types').PageServerLoad} */export async functionload ({parent }) {const {a ,b } = awaitparent ();console .log (a ,b ); // `1`, `2`return {c : 3 };}
src/routes/foo/+page.server.ts
ts
import type {PageServerLoad } from './$types';export constload :PageServerLoad = async ({parent }) => {const {a ,b } = awaitparent ();console .log (a ,b ); // `1`, `2`return {c : 3 };}
In +page.js
or +layout.js
it will return data from load
functions in parent +layout.js
files. Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will also return data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
src/routes/foo/+page.server.js
// @filename: $types.d.ts
export type PageServerLoad = import('@sveltejs/kit').Load<{}, null, { a: number, b: number }>;
// @filename: index.js
// ---cut---
/** @type {import('./$types').PageServerLoad} */
export async function load({ parent, fetch }) {
const parentData = await parent();
const data = await fetch('./some-api');
const parentData = await parent();
return {
...data
meta: { ...parentData.meta, ...data.meta }
};
}
setHeaderspermalink
If you need to set headers for the response, you can do so using the setHeaders
method. This is useful if you want the page to be cached, for example:
src/routes/blog/+page.js
ts
/** @type {import('./$types').PageLoad} */export async functionload ({fetch ,setHeaders }) {consturl = `https://cms.example.com/articles.json`;constresponse = awaitfetch (url );setHeaders ({age :response .headers .get ('age'),'cache-control':response .headers .get ('cache-control')});returnresponse .json ();}
src/routes/blog/+page.ts
ts
import type {PageLoad } from './$types';export constload :PageLoad = async ({fetch ,setHeaders }) => {consturl = `https://cms.example.com/articles.json`;constresponse = awaitfetch (url );setHeaders ({age :response .headers .get ('age'),'cache-control':response .headers .get ('cache-control')});returnresponse .json ();}
setHeaders
has no effect when aload
function runs in the browser.
Setting the same header multiple times (even in separate load
functions) is an error — you can only set a given header once.
You cannot add a set-cookie
header with setHeaders
— use the cookies
API in a server-only load
function instead.
Outputpermalink
The returned data
, if any, must be an object of values. For a server-only load
function, these values must be serializable with devalue. Top-level promises will be awaited, which makes it easy to return multiple promises without creating a waterfall:
ts
/** @type {import('./$types').PageLoad} */export functionload () {return {a :Promise .resolve ('a'),b :Promise .resolve ('b'),c : {value :Promise .resolve ('c')}};}
<script>
/** @type {import('./$types').PageData} */ export let data;
console.log(data.a); // 'a'
console.log(data.b); // 'b'
console.log(data.c.value); // `Promise {...}`
</script>
Errorspermalink
If an error is thrown during load
, the nearest +error.svelte
will be rendered. For expected errors, use the error
helper from @sveltejs/kit
to specify the HTTP status code and an optional message:
src/routes/admin/+layout.server.js
ts
import {error } from '@sveltejs/kit';/** @type {import('./$types').LayoutServerLoad} */export functionload ({locals }) {if (!locals .user ) {throwerror (401, 'not logged in');}if (!locals .user .isAdmin ) {throwerror (403, 'not an admin');}}
src/routes/admin/+layout.server.ts
ts
import {error } from '@sveltejs/kit';import type {LayoutServerLoad } from './$types';export constload :LayoutServerLoad = ({locals }) => {if (!locals .user ) {throwerror (401, 'not logged in');}if (!locals .user .isAdmin ) {throwerror (403, 'not an admin');}}
If an unexpected error is thrown, SvelteKit will invoke handleError
and treat it as a 500 Internal Error.
Redirectspermalink
To redirect users, use the redirect
helper from @sveltejs/kit
to specify the location to which they should be redirected alongside a 3xx
status code.
src/routes/admin/+layout.server.js
import { error } from '@sveltejs/kit';
import { error, redirect } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function load({ locals }) {
if (!locals.user) {
throw error(401, 'not logged in');
throw redirect(307, '/login');
}
if (!locals.user.isAdmin) {
throw error(403, 'not an admin');
}
}
Invalidationpermalink
SvelteKit tracks the dependencies of each load
function to avoid re-running it unnecessarily during navigation. For example, a load
function in a root +layout.js
doesn't need to re-run when you navigate from one page to another unless it references url
or a member of params
that changed since the last navigation.
A load
function will re-run in the following situations:
- It references a property of
params
whose value has changed - It references a property of
url
(such asurl.pathname
orurl.search
) whose value has changed - It calls
await parent()
and a parentload
function re-ran - It declared a dependency on a specific URL via
fetch
ordepends
, and that URL was marked invalid withinvalidate(url)
- All active
load
functions were forcibly re-run withinvalidateAll()
If a load
function is triggered to re-run, the page will not remount — instead, it will update with the new data
. This means that components' internal state is preserved. If this isn't want you want, you can reset whatever you need to reset inside an afterNavigate
callback, and/or wrap your component in a {#key ...}
block.
Shared statepermalink
In many server environments, a single instance of your app will serve multiple users. For that reason, per-request state must not be stored in shared variables outside your load
functions, but should instead be stored in event.locals
. Similarly, per-user state must not be stored in global variables, but should instead make use of $page.data
(which contains the combined data of all load
functions) or use Svelte's context feature to create scoped state.