Getting started
Core concepts
Build and deploy
Advanced
Best practices
Appendix
Reference
- @sveltejs/kit
- @sveltejs/kit/hooks
- @sveltejs/kit/node/polyfills
- @sveltejs/kit/node
- @sveltejs/kit/vite
- $app/environment
- $app/forms
- $app/navigation
- $app/paths
- $app/server
- $app/state
- $app/stores
- $app/types
- $env/dynamic/private
- $env/dynamic/public
- $env/static/private
- $env/static/public
- $lib
- $service-worker
- Configuration
- Command Line Interface
- Types
Loading data
Before a+page.svelte component (and its containing+layout.svelte components) can be rendered, we often need to get some data. This is done by definingload functions.
Page data
A+page.svelte file can have a sibling+page.js that exports aload function, the return value of which is available to the page via thedata prop:
/**@type{import('./$types').PageLoad}*/exportfunctionfunctionload({ params }:{params:any;}):{post:{title:string;content:string;};}
@type{import('./$types').PageLoad}load({params:anyparams}) {return{post:{title:string;content:string;}
post:{title:stringtitle:`Title for${params:anyparams.slug}goes here`,content:stringcontent:`Content for${params:anyparams.slug}goes here`}};}importtype{typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad}from'./$types';exportconstconstload:PageLoadload:typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad=({params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params})=>{return{post:{title:string;content:string;}
post:{title:stringtitle:`Title for${params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params.slug}goes here`,content:stringcontent:`Content for${params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params.slug}goes here`}};};<script>/**@type{import('./$types').PageProps}*/let{ data }=$props();</script><h1>{data.post.title}</h1><div>{@htmldata.post.content}</div><scriptlang="ts">importtype{ PageProps }from'./$types';let{ data }:PageProps=$props();</script><h1>{data.post.title}</h1><div>{@htmldata.post.content}</div>Legacy mode
Before version 2.16.0, the props of a page and layout had to be typed individually:
+page/**@type{{ data: import('./$types').PageData }}*/let{letdata:anydata}=function$props():anynamespace$props$props();Declares the props that a component accepts. Example:
let{ optionalProp=42,requiredProp,bindableProp=$bindable() }:{ optionalProp?:number; requiredProps:string; bindableProp:boolean}=$props();importtype{importPageDataPageData}from'./$types';let{letdata:PageDatadata}:{data:PageDatadata:importPageDataPageData}=function$props():anynamespace$props$props();Declares the props that a component accepts. Example:
let{ optionalProp=42,requiredProp,bindableProp=$bindable() }:{ optionalProp?:number; requiredProps:string; bindableProp:boolean}=$props();In Svelte 4, you’d use
export let datainstead.
Thanks to the generated$types module, we get full type safety.
Aload function in a+page.js file runs both on the server and in the browser (unless combined withexport const ssr = false, in which case it willonly run in the browser). If yourload function shouldalways run on the server (because it uses private environment variables, for example, or accesses a database) then it would go in a+page.server.js instead.
A more realistic version of your blog post’sload function, that only runs on the server and pulls data from a database, might look like this:
import*asmodule"$lib/server/database"dbfrom'$lib/server/database';/**@type{import('./$types').PageServerLoad}*/exportasyncfunctionfunctionload(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>):MaybePromise<void|Record<string,any>>@type{import('./$types').PageServerLoad}load({params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params}) {return{post:{title:string;content:string;}
post:awaitmodule"$lib/server/database"db.functiongetPost(slug:string):Promise<{title:string;content:string;}>
getPost(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug)};}import*asmodule"$lib/server/database"dbfrom'$lib/server/database';importtype{typePageServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>PageServerLoad}from'./$types';exportconstconstload:PageServerLoadload:typePageServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>PageServerLoad=async({params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params})=>{return{post:{title:string;content:string;}
post:awaitmodule"$lib/server/database"db.functiongetPost(slug:string):Promise<{title:string;content:string;}>
getPost(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug)};};Notice that the type changed fromPageLoad toPageServerLoad, because serverload functions can access additional arguments. To understand when to use+page.js and when to use+page.server.js, seeUniversal vs server.
Layout data
Your+layout.svelte files can also load data, via+layout.js or+layout.server.js.
import*asmodule"$lib/server/database"dbfrom'$lib/server/database';/**@type{import('./$types').LayoutServerLoad}*/exportasyncfunctionfunctionload(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>):MaybePromise<void|Record<string,any>>@type{import('./$types').LayoutServerLoad}load() {return{posts:{title:string;slug:string;}[]
posts:awaitmodule"$lib/server/database"db.functiongetPostSummaries():Promise<Array<{title:string;slug:string;}>>
getPostSummaries()};}import*asmodule"$lib/server/database"dbfrom'$lib/server/database';importtype{typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad}from'./$types';exportconstconstload:LayoutServerLoadload:typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad=async()=>{return{posts:{title:string;slug:string;}[]
posts:awaitmodule"$lib/server/database"db.functiongetPostSummaries():Promise<Array<{title:string;slug:string;}>>
getPostSummaries()};};<script>/**@type{import('./$types').LayoutProps}*/let{ data,children }=$props();</script><main><!-- +page.svelte is `@render`ed here -->{@renderchildren()}</main><aside><h2>More posts</h2><ul>{#eachdata.postsaspost}<li><ahref="/blog/{post.slug}">{post.title}</a></li>{/each}</ul></aside><scriptlang="ts">importtype{ LayoutProps }from'./$types';let{ data,children }:LayoutProps=$props();</script><main><!-- +page.svelte is `@render`ed here -->{@renderchildren()}</main><aside><h2>More posts</h2><ul>{#eachdata.postsaspost}<li><ahref="/blog/{post.slug}">{post.title}</a></li>{/each}</ul></aside>Legacy mode
LayoutPropswas added in 2.16.0. In earlier versions, properties had to be typed individually:+layout/**@type{{ data: import('./$types').LayoutData, children: Snippet }}*/let{letdata:anydata,letchildren:anychildren}=function$props():anynamespace$props$props();Declares the props that a component accepts. Example:
let{ optionalProp=42,requiredProp,bindableProp=$bindable() }:{ optionalProp?:number; requiredProps:string; bindableProp:boolean}=$props();importtype{importLayoutDataLayoutData}from'./$types';let{letdata:LayoutDatadata,letchildren:Snippetchildren}:{data:LayoutDatadata:importLayoutDataLayoutData,children:Snippetchildren:typeSnippet=/*unresolved*/anySnippet}=function$props():anynamespace$props$props();Declares the props that a component accepts. Example:
let{ optionalProp=42,requiredProp,bindableProp=$bindable() }:{ optionalProp?:number; requiredProps:string; bindableProp:boolean}=$props();
Data returned from layoutload functions is available to child+layout.svelte components and the+page.svelte component as well as the layout that it ‘belongs’ to.
<script>import{ page }from'$app/state';/**@type{import('./$types').PageProps}*/let{ data }=$props();// we can access `data.posts` because it's returned from// the parent layout `load` functionletindex=$derived(data.posts.findIndex(post=>post.slug===page.params.slug));letnext=$derived(data.posts[index+1]);</script><h1>{data.post.title}</h1><div>{@htmldata.post.content}</div>{#ifnext}<p>Next post: <ahref="/blog/{next.slug}">{next.title}</a></p>{/if}<scriptlang="ts">import{ page }from'$app/state';importtype{ PageProps }from'./$types';let{ data }:PageProps=$props();// we can access `data.posts` because it's returned from// the parent layout `load` functionletindex=$derived(data.posts.findIndex(post=>post.slug===page.params.slug));letnext=$derived(data.posts[index+1]);</script><h1>{data.post.title}</h1><div>{@htmldata.post.content}</div>{#ifnext}<p>Next post: <ahref="/blog/{next.slug}">{next.title}</a></p>{/if}If multiple
loadfunctions return data with the same key, the last one ‘wins’ — the result of a layoutloadreturning{ a: 1, b: 2 }and a pageloadreturning{ b: 3, c: 4 }would be{ a: 1, b: 3, c: 4 }.
page.data
The+page.svelte component, and each+layout.svelte component above it, has access to its own data plus all the data from its parents.
In some cases, we might need the opposite — a parent layout might need to access page data or data from a child layout. For example, the root layout might want to access atitle property returned from aload function in+page.js or+page.server.js. This can be done withpage.data:
<script>import{ page }from'$app/state';</script><svelte:head><title>{page.data.title}</title></svelte:head><scriptlang="ts">import{ page }from'$app/state';</script><svelte:head><title>{page.data.title}</title></svelte:head>Type information forpage.data is provided byApp.PageData.
Legacy mode
$app/statewas added in SvelteKit 2.12. If you’re using an earlier version or are using Svelte 4, use$app/storesinstead.It provides apagestore with the same interface that you can subscribe to, e.g.$page.data.title.
Universal vs server
As we’ve seen, there are two types ofload function:
+page.jsand+layout.jsfiles exportuniversalloadfunctions that run both on the server and in the browser+page.server.jsand+layout.server.jsfiles exportserverloadfunctions that only run server-side
Conceptually, they’re the same thing, but there are some important differences to be aware of.
When does which load function run?
Serverload functionsalways run on the server.
By default, universalload functions run on the server during SSR when the user first visits your page. They will then run again during hydration, reusing any responses fromfetch requests. All subsequent invocations of universalload functions happen in the browser. You can customize the behavior throughpage options. If you disableserver-side rendering, you’ll get an SPA and universalload functionsalways run on the client.
If a route contains both universal and serverload functions, the serverload runs first.
Aload function is invoked at runtime, unless youprerender the page — in that case, it’s invoked at build time.
Input
Both universal and serverload functions have access to properties describing the request (params,route andurl) and various functions (fetch,setHeaders,parent,depends anduntrack). These are described in the following sections.
Serverload functions are called with aServerLoadEvent, which inheritsclientAddress,cookies,locals,platform andrequest fromRequestEvent.
Universalload functions are called with aLoadEvent, which has adata property. If you haveload functions in both+page.js and+page.server.js (or+layout.js and+layout.server.js), the return value of the serverload function is thedata property of the universalload function’s argument.
Output
A universalload function can return an object containing any values, including things like custom classes and component constructors.
A serverload function must return data that can be serialized withdevalue — anything that can be represented as JSON plus things likeBigInt,Date,Map,Set andRegExp, or repeated/cyclical references — so that it can be transported over the network. Your data can includepromises, in which case it will be streamed to browsers. If you need to serialize/deserialize custom types, usetransport hooks.
When to use which
Serverload functions are convenient when you need to access data directly from a database or filesystem, or need to use private environment variables.
Universalload functions are useful when you need tofetch data from an external API and don’t need private credentials, since SvelteKit can get the data directly from the API rather than going via your server. They are also useful when you need to return something that can’t be serialized, such as a Svelte component constructor.
In rare cases, you might need to use both together — for example, you might need to return an instance of a custom class that was initialised with data from your server. When using both, the serverload return value isnot passed directly to the page, but to the universalload function (as thedata property):
/**@type{import('./$types').PageServerLoad}*/exportasyncfunctionfunctionload():Promise<{serverMessage:string;}>
@type{import('./$types').PageServerLoad}load() {return{serverMessage:stringserverMessage:'hello from server load function'};}importtype{typePageServerLoad=(event:Kit.ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageServerLoad=(event:Kit.ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageServerLoad}from'./$types';exportconstconstload:PageServerLoadload:typePageServerLoad=(event:Kit.ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageServerLoad=(event:Kit.ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageServerLoad=async()=>{return{serverMessage:stringserverMessage:'hello from server load function'};};/**@type{import('./$types').PageLoad}*/exportasyncfunctionfunctionload({ data }:{data:any;}):Promise<{serverMessage:any;universalMessage:string;}>
@type{import('./$types').PageLoad}load({data:anydata}) {return{serverMessage:anyserverMessage:data:anydata.serverMessage,universalMessage:stringuniversalMessage:'hello from universal load function'};}importtype{typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad}from'./$types';exportconstconstload:PageLoadload:typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad=async({data:Record<string,any>|nullContains the data returned by the route’s serverload function (in+layout.server.js or+page.server.js), if any.
data})=>{return{serverMessage:anyserverMessage:data:Record<string,any>|nullContains the data returned by the route’s serverload function (in+layout.server.js or+page.server.js), if any.
data.serverMessage,universalMessage:stringuniversalMessage:'hello from universal load function'};};Using URL data
Often theload function depends on the URL in one way or another. For this, theload function provides you withurl,route andparams.
url
An instance ofURL, containing properties like theorigin,hostname,pathname andsearchParams (which contains the parsed query string as aURLSearchParams object).url.hash cannot be accessed duringload, since it is unavailable on the server.
In some environments this is derived from request headers during server-side rendering. If you’re usingadapter-node, for example, you may need to configure the adapter in order for the URL to be correct.
route
Contains the name of the current route directory, relative tosrc/routes:
/**@type{import('./$types').PageLoad}*/exportfunctionfunctionload({ route }:{route:any;}):void
@type{import('./$types').PageLoad}load({route:anyroute}) {varconsole:ConsoleTheconsole module provides a simple debugging console that is similar to theJavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console class with methods such asconsole.log(),console.error() andconsole.warn() that can be used to write to any Node.js stream. - A global
console instance configured to write toprocess.stdout andprocess.stderr. The globalconsole can be used without importing thenode:console module.
Warning: The global console object’s methods are neither consistentlysynchronous like the browser APIs they resemble, nor are they consistentlyasynchronous like all other Node.js streams. See thenote on process I/O formore information.
Example using the globalconsole:
console.log('hello world');// Prints: hello world, to stdoutconsole.log('hello %s','world');// Prints: hello world, to stdoutconsole.error(newError('Whoops, something bad happened'));// Prints error message and stack trace to stderr:// Error: Whoops, something bad happened// at [eval]:5:15// at Script.runInThisContext (node:vm:132:18)// at Object.runInThisContext (node:vm:309:38)// at node:internal/process/execution:77:19// at [eval]-wrapper:6:22// at evalScript (node:internal/process/execution:76:60)// at node:internal/main/eval_string:23:3constname='Will Robinson';console.warn(`Danger${name}! Danger!`);// Prints: Danger Will Robinson! Danger!, to stderr
Example using theConsole class:
constout=getStreamSomehow();consterr=getStreamSomehow();constmyConsole=newconsole.Console(out,err);myConsole.log('hello world');// Prints: hello world, to outmyConsole.log('hello %s','world');// Prints: hello world, to outmyConsole.error(newError('Whoops, something bad happened'));// Prints: [Error: Whoops, something bad happened], to errconstname='Will Robinson';myConsole.warn(`Danger${name}! Danger!`);// Prints: Danger Will Robinson! Danger!, to err
@seesourceconsole.Console.log(message?:any,...optionalParams: any[]):void(+1overload)Prints tostdout with newline. Multiple arguments can be passed, with thefirst used as the primary message and all additional used as substitutionvalues similar toprintf(3)(the arguments are all passed toutil.format()).
constcount=5;console.log('count: %d',count);// Prints: count: 5, to stdoutconsole.log('count:',count);// Prints: count: 5, to stdout
Seeutil.format() for more information.
@sincev0.1.100log(route:anyroute.id);// '/a/[b]/[...c]'}importtype{typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad}from'./$types';exportconstconstload:PageLoadload:typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad=({route:{id:string|null;}
Info about the current route
route})=>{varconsole:ConsoleTheconsole module provides a simple debugging console that is similar to theJavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console class with methods such asconsole.log(),console.error() andconsole.warn() that can be used to write to any Node.js stream. - A global
console instance configured to write toprocess.stdout andprocess.stderr. The globalconsole can be used without importing thenode:console module.
Warning: The global console object’s methods are neither consistentlysynchronous like the browser APIs they resemble, nor are they consistentlyasynchronous like all other Node.js streams. See thenote on process I/O formore information.
Example using the globalconsole:
console.log('hello world');// Prints: hello world, to stdoutconsole.log('hello %s','world');// Prints: hello world, to stdoutconsole.error(newError('Whoops, something bad happened'));// Prints error message and stack trace to stderr:// Error: Whoops, something bad happened// at [eval]:5:15// at Script.runInThisContext (node:vm:132:18)// at Object.runInThisContext (node:vm:309:38)// at node:internal/process/execution:77:19// at [eval]-wrapper:6:22// at evalScript (node:internal/process/execution:76:60)// at node:internal/main/eval_string:23:3constname='Will Robinson';console.warn(`Danger${name}! Danger!`);// Prints: Danger Will Robinson! Danger!, to stderr
Example using theConsole class:
constout=getStreamSomehow();consterr=getStreamSomehow();constmyConsole=newconsole.Console(out,err);myConsole.log('hello world');// Prints: hello world, to outmyConsole.log('hello %s','world');// Prints: hello world, to outmyConsole.error(newError('Whoops, something bad happened'));// Prints: [Error: Whoops, something bad happened], to errconstname='Will Robinson';myConsole.warn(`Danger${name}! Danger!`);// Prints: Danger Will Robinson! Danger!, to err
@seesourceconsole.Console.log(message?:any,...optionalParams: any[]):void(+1overload)Prints tostdout with newline. Multiple arguments can be passed, with thefirst used as the primary message and all additional used as substitutionvalues similar toprintf(3)(the arguments are all passed toutil.format()).
constcount=5;console.log('count: %d',count);// Prints: count: 5, to stdoutconsole.log('count:',count);// Prints: count: 5, to stdout
Seeutil.format() for more information.
@sincev0.1.100log(route:{id:string|null;}
Info about the current route
route.id:string|nullThe ID of the current route - e.g. forsrc/routes/blog/[slug], it would be/blog/[slug]. It isnull when no route is matched.
id);// '/a/[b]/[...c]'};params
params is derived fromurl.pathname androute.id.
Given aroute.id of/a/[b]/[...c] and aurl.pathname of/a/x/y/z, theparams object would look like this:
{"b": "x","c": "y/z"}Making fetch requests
To get data from an external API or a+server.js handler, you can use the providedfetch function, which behaves identically to thenativefetch web API with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookieandauthorizationheaders for the page request. - It can make relative requests on the server (ordinarily,
fetchrequires a URL with an origin when used in a server context). - Internal requests (e.g. for
+server.jsroutes) go directly 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 by hooking into the
text,jsonandarrayBuffermethods of theResponseobject. Note that headers willnot be serialized, unless explicitly included viafilterSerializedResponseHeaders. - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request - if you received a warning in your browser console when using the browser
fetchinstead of theloadfetch, this is why.
/**@type{import('./$types').PageLoad}*/exportasyncfunctionfunctionload({ fetch,params }:{fetch:any;params:any;}):Promise<{item:any;}>
@type{import('./$types').PageLoad}load({fetch:anyfetch,params:anyparams}) {constconstres:anyres=awaitfetch:anyfetch(`/api/items/${params:anyparams.id}`);constconstitem:anyitem=awaitconstres:anyres.json();return{item:anyitem};}importtype{typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad}from'./$types';exportconstconstload:PageLoadload:typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad=async({fetch:{(input:RequestInfo|URL,init?:RequestInit):Promise<Response>;(input:string|URL|globalThis.Request,init?:RequestInit):Promise<Response>;}
fetch is equivalent to thenativefetch 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 directly 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 by hooking into the
text andjson methods of theResponse object. Note that headers willnot be serialized, unless explicitly included viafilterSerializedResponseHeaders - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookieshere
fetch,params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params})=>{constconstres:Responseres=awaitfetch:(input:string|URL|globalThis.Request,init?:RequestInit)=>Promise<Response> (+1overload)fetch(`/api/items/${params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params.id}`);constconstitem:anyitem=awaitconstres:Responseres.Body.json():Promise<any>json();return{item:anyitem};};Cookies
A serverload function can get and setcookies.
import*asmodule"$lib/server/database"dbfrom'$lib/server/database';/**@type{import('./$types').LayoutServerLoad}*/exportasyncfunctionfunctionload(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>):MaybePromise<void|Record<string,any>>@type{import('./$types').LayoutServerLoad}load({cookies:CookiesGet or set cookies related to the current request
cookies}) {constconstsessionid:string|undefinedsessionid=cookies:CookiesGet or set cookies related to the current request
cookies.Cookies.get: (name:string,opts?:CookieParseOptions)=>string|undefinedGets a cookie that was previously set withcookies.set, or from the request headers.
@paramname the name of the cookie@paramopts the options, passed directly tocookie.parse. See documentationhereget('sessionid');return{user:{name:string;avatar:string;}
user:awaitmodule"$lib/server/database"db.functiongetUser(sessionid:string|undefined):Promise<{name:string;avatar:string;}>
getUser(constsessionid:string|undefinedsessionid)};}import*asmodule"$lib/server/database"dbfrom'$lib/server/database';importtype{typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad}from'./$types';exportconstconstload:LayoutServerLoadload:typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad=async({cookies:CookiesGet or set cookies related to the current request
cookies})=>{constconstsessionid:string|undefinedsessionid=cookies:CookiesGet or set cookies related to the current request
cookies.Cookies.get: (name:string,opts?:CookieParseOptions)=>string|undefinedGets a cookie that was previously set withcookies.set, or from the request headers.
@paramname the name of the cookie@paramopts the options, passed directly tocookie.parse. See documentationhereget('sessionid');return{user:{name:string;avatar:string;}
user:awaitmodule"$lib/server/database"db.functiongetUser(sessionid:string|undefined):Promise<{name:string;avatar:string;}>
getUser(constsessionid:string|undefinedsessionid)};};Cookies will only be passed through the providedfetch function if the target host is the same as the SvelteKit application or a more specific subdomain of it.
For example, if SvelteKit is serving my.domain.com:
- domain.com WILL NOT receive cookies
- my.domain.com WILL receive cookies
- api.domain.com WILL NOT receive cookies
- sub.my.domain.com WILL receive cookies
Other cookies will not be passed whencredentials: 'include' is set, because SvelteKit does not know which domain which cookie belongs to (the browser does not pass this information along), so it’s not safe to forward any of them. Use thehandleFetch hook to work around it.
Headers
Both server and universalload functions have access to asetHeaders function that, when running on the server, can set headers for the response. (When running in the browser,setHeaders has no effect.) This is useful if you want the page to be cached, for example:
/**@type{import('./$types').PageLoad}*/exportasyncfunctionfunctionload({ fetch,setHeaders }:{fetch:any;setHeaders:any;}):Promise<any>
@type{import('./$types').PageLoad}load({fetch:anyfetch,setHeaders:anysetHeaders}) {constconsturl:"https://cms.example.com/products.json"url=`https://cms.example.com/products.json`;constconstresponse:anyresponse=awaitfetch:anyfetch(consturl:"https://cms.example.com/products.json"url);// Headers are only set during SSR, caching the page's HTML// for the same length of time as the underlying data.setHeaders:anysetHeaders({age:anyage:constresponse:anyresponse.headers.get('age'),'cache-control':constresponse:anyresponse.headers.get('cache-control')});returnconstresponse:anyresponse.json();}importtype{typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad}from'./$types';exportconstconstload:PageLoadload:typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad=async({fetch:{(input:RequestInfo|URL,init?:RequestInit):Promise<Response>;(input:string|URL|globalThis.Request,init?:RequestInit):Promise<Response>;}
fetch is equivalent to thenativefetch 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 directly 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 by hooking into the
text andjson methods of theResponse object. Note that headers willnot be serialized, unless explicitly included viafilterSerializedResponseHeaders - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookieshere
fetch,setHeaders:(headers:Record<string,string>)=>voidIf you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
src/routes/blog/+pageexportasyncfunctionload({ 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();}
Setting the same header multiple times (even in separateload functions) is an error — you can only set a given header once.
You cannot add aset-cookie header withsetHeaders — use thecookies API in a server-onlyload function instead.
setHeaders has no effect when aload function runs in the browser.
setHeaders})=>{constconsturl:"https://cms.example.com/products.json"url=`https://cms.example.com/products.json`;constconstresponse:Responseresponse=awaitfetch:(input:string|URL|globalThis.Request,init?:RequestInit)=>Promise<Response> (+1overload)fetch(consturl:"https://cms.example.com/products.json"url);// Headers are only set during SSR, caching the page's HTML// for the same length of time as the underlying data.setHeaders:(headers:Record<string,string>)=>voidIf you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
src/routes/blog/+pageexportasyncfunctionload({ 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();}
Setting the same header multiple times (even in separateload functions) is an error — you can only set a given header once.
You cannot add aset-cookie header withsetHeaders — use thecookies API in a server-onlyload function instead.
setHeaders has no effect when aload function runs in the browser.
setHeaders({age:string|nullage:constresponse:Responseresponse.Response.headers: Headersheaders.Headers.get(name: string): string|nullget('age'),'cache-control':constresponse:Responseresponse.Response.headers: Headersheaders.Headers.get(name: string): string|nullget('cache-control')});returnconstresponse:Responseresponse.Body.json():Promise<any>json();};Setting the same header multiple times (even in separateload functions) is an error. You can only set a given header once using thesetHeaders function. You cannot add aset-cookie header withsetHeaders — usecookies.set(name, value, options) instead.
Using parent data
Occasionally it’s useful for aload function to access data from a parentload function, which can be done withawait parent():
/**@type{import('./$types').LayoutLoad}*/exportfunctionfunctionload():{a:number;}
@type{import('./$types').LayoutLoad}load() {return{a:numbera:1};}importtype{typeLayoutLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typeLayoutLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
LayoutLoad}from'./$types';exportconstconstload:LayoutLoadload:typeLayoutLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typeLayoutLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
LayoutLoad=()=>{return{a:numbera:1};};/**@type{import('./$types').LayoutLoad}*/exportasyncfunctionfunctionload({ parent }:{parent:any;}):Promise<{b:any;}>
@type{import('./$types').LayoutLoad}load({parent:anyparent}) {const{consta:anya}=awaitparent:anyparent();return{b:anyb:consta:anya+1};}importtype{typeLayoutLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typeLayoutLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
LayoutLoad}from'./$types';exportconstconstload:LayoutLoadload:typeLayoutLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typeLayoutLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
LayoutLoad=async({parent:()=>Promise<Record<string,any>>await parent() returns data from parent+layout.jsload functions.Implicitly, a missing+layout.js is treated as a({ data }) => data function, meaning that it will return and forward data from parent+layout.server.js files.
Be careful not to introduce accidental waterfalls when usingawait parent(). If for example you only want to merge parent data into the returned output, call itafter fetching your other data.
parent})=>{const{consta:anya}=awaitparent:()=>Promise<Record<string,any>>await parent() returns data from parent+layout.jsload functions.Implicitly, a missing+layout.js is treated as a({ data }) => data function, meaning that it will return and forward data from parent+layout.server.js files.
Be careful not to introduce accidental waterfalls when usingawait parent(). If for example you only want to merge parent data into the returned output, call itafter fetching your other data.
parent();return{b:anyb:consta:anya+1};};/**@type{import('./$types').PageLoad}*/exportasyncfunctionfunctionload({ parent }:{parent:any;}):Promise<{c:any;}>
@type{import('./$types').PageLoad}load({parent:anyparent}) {const{consta:anya,constb:anyb}=awaitparent:anyparent();return{c:anyc:consta:anya+constb:anyb};}importtype{typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad}from'./$types';exportconstconstload:PageLoadload:typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad=async({parent:()=>Promise<Record<string,any>>await parent() returns data from parent+layout.jsload functions.Implicitly, a missing+layout.js is treated as a({ data }) => data function, meaning that it will return and forward data from parent+layout.server.js files.
Be careful not to introduce accidental waterfalls when usingawait parent(). If for example you only want to merge parent data into the returned output, call itafter fetching your other data.
parent})=>{const{consta:anya,constb:anyb}=awaitparent:()=>Promise<Record<string,any>>await parent() returns data from parent+layout.jsload functions.Implicitly, a missing+layout.js is treated as a({ data }) => data function, meaning that it will return and forward data from parent+layout.server.js files.
Be careful not to introduce accidental waterfalls when usingawait parent(). If for example you only want to merge parent data into the returned output, call itafter fetching your other data.
parent();return{c:anyc:consta:anya+constb:anyb};};<script>/**@type{import('./$types').PageProps}*/let{ data }=$props();</script><!-- renders `1 + 2 = 3` --><p>{data.a} + {data.b} = {data.c}</p><scriptlang="ts">importtype{ PageProps }from'./$types';let{ data }:PageProps=$props();</script><!-- renders `1 + 2 = 3` --><p>{data.a} + {data.b} = {data.c}</p>Notice that the
loadfunction in+page.jsreceives the merged data from both layoutloadfunctions, not just the immediate parent.
Inside+page.server.js and+layout.server.js,parent returns data from parent+layout.server.js files.
In+page.js or+layout.js it will return data from parent+layout.js files. However, a missing+layout.js is treated as a({ data }) => data function, meaning that it will also return data from parent+layout.server.js files that are not ‘shadowed’ by a+layout.js file
Take care not to introduce waterfalls when usingawait parent(). Here, for example,getData(params) does not depend on the result of callingparent(), so we should call it first to avoid a delayed render.
/**@type{import('./$types').PageLoad}*/exportasyncfunctionfunctionload(event:LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>):MaybePromise<void|Record<string,any>>@type{import('./$types').PageLoad}load({params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params,parent:()=>Promise<Record<string,any>>await parent() returns data from parent+layout.jsload functions.Implicitly, a missing+layout.js is treated as a({ data }) => data function, meaning that it will return and forward data from parent+layout.server.js files.
Be careful not to introduce accidental waterfalls when usingawait parent(). If for example you only want to merge parent data into the returned output, call itafter fetching your other data.
parent}) {const parentData = await parent();constconstdata:{meta:any;}
data=awaitfunctiongetData(params:Record<string,string>):Promise<{meta:any;}>
getData(params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params);constconstparentData:Record<string,any>parentData=awaitparent:()=>Promise<Record<string,any>>await parent() returns data from parent+layout.jsload functions.Implicitly, a missing+layout.js is treated as a({ data }) => data function, meaning that it will return and forward data from parent+layout.server.js files.
Be careful not to introduce accidental waterfalls when usingawait parent(). If for example you only want to merge parent data into the returned output, call itafter fetching your other data.
parent();return{...constdata:{meta:any;}
data,meta:anymeta:{...constparentData:Record<string,any>parentData.meta,...constdata:{meta:any;}
data.meta:anymeta}};}importtype{typePageLoad=(event:LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>PageLoad}from'./$types';exportconstconstload:PageLoadload:typePageLoad=(event:LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>PageLoad=async({params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params,parent:()=>Promise<Record<string,any>>await parent() returns data from parent+layout.jsload functions.Implicitly, a missing+layout.js is treated as a({ data }) => data function, meaning that it will return and forward data from parent+layout.server.js files.
Be careful not to introduce accidental waterfalls when usingawait parent(). If for example you only want to merge parent data into the returned output, call itafter fetching your other data.
parent})=>{const parentData = await parent();constconstdata:{meta:any;}
data=awaitfunctiongetData(params:Record<string,string>):Promise<{meta:any;}>
getData(params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params);constconstparentData:Record<string,any>parentData=awaitparent:()=>Promise<Record<string,any>>await parent() returns data from parent+layout.jsload functions.Implicitly, a missing+layout.js is treated as a({ data }) => data function, meaning that it will return and forward data from parent+layout.server.js files.
Be careful not to introduce accidental waterfalls when usingawait parent(). If for example you only want to merge parent data into the returned output, call itafter fetching your other data.
parent();return{...constdata:{meta:any;}
data,meta:anymeta:{...constparentData:Record<string,any>parentData.meta,...constdata:{meta:any;}
data.meta:anymeta}};};Errors
If an error is thrown duringload, the nearest+error.svelte will be rendered. Forexpected errors, use theerror helper from@sveltejs/kit to specify the HTTP status code and an optional message:
import{functionerror(status:number,body:App.Error):never(+1overload)Throws an error with a HTTP status code and an optional message.When called during request handling, this will cause SvelteKit toreturn an error response without invokinghandleError.Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
@paramstatus TheHTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error}from'@sveltejs/kit';/**@type{import('./$types').LayoutServerLoad}*/exportfunctionfunctionload(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>):MaybePromise<void|Record<string,any>>@type{import('./$types').LayoutServerLoad}load({locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals}) {if(!locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals.App.Locals.user?:{name:string;isAdmin: boolean;}|undefined
user) {functionerror(status:number,body?:{message:string;}extendsApp.Error?App.Error|string|undefined:never):never(+1overload)
Throws an error with a HTTP status code and an optional message.When called during request handling, this will cause SvelteKit toreturn an error response without invokinghandleError.Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
@paramstatus TheHTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(401,'not logged in');}if(!locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals.App.Locals.user?:{name:string;isAdmin: boolean;}
user.isAdmin:booleanisAdmin) {functionerror(status:number,body?:{message:string;}extendsApp.Error?App.Error|string|undefined:never):never(+1overload)
Throws an error with a HTTP status code and an optional message.When called during request handling, this will cause SvelteKit toreturn an error response without invokinghandleError.Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
@paramstatus TheHTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(403,'not an admin');}}import{functionerror(status:number,body:App.Error):never(+1overload)Throws an error with a HTTP status code and an optional message.When called during request handling, this will cause SvelteKit toreturn an error response without invokinghandleError.Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
@paramstatus TheHTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error}from'@sveltejs/kit';importtype{typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad}from'./$types';exportconstconstload:LayoutServerLoadload:typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad=({locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals})=>{if(!locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals.App.Locals.user?:{name:string;isAdmin: boolean;}|undefined
user) {functionerror(status:number,body?:{message:string;}extendsApp.Error?App.Error|string|undefined:never):never(+1overload)
Throws an error with a HTTP status code and an optional message.When called during request handling, this will cause SvelteKit toreturn an error response without invokinghandleError.Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
@paramstatus TheHTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(401,'not logged in');}if(!locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals.App.Locals.user?:{name:string;isAdmin: boolean;}
user.isAdmin:booleanisAdmin) {functionerror(status:number,body?:{message:string;}extendsApp.Error?App.Error|string|undefined:never):never(+1overload)
Throws an error with a HTTP status code and an optional message.When called during request handling, this will cause SvelteKit toreturn an error response without invokinghandleError.Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
@paramstatus TheHTTP status code. Must be in the range 400-599.@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.@throwsError If the provided status is invalid (not between 400 and 599).error(403,'not an admin');}};Callingerror(...) will throw an exception, making it easy to stop execution from inside helper functions.
If anunexpected error is thrown, SvelteKit will invokehandleError and treat it as a 500 Internal Error.
In SvelteKit 1.x you had to
throwthe error yourself
Redirects
To redirect users, use theredirect helper from@sveltejs/kit to specify the location to which they should be redirected alongside a3xx status code. Likeerror(...), callingredirect(...) will throw an exception, making it easy to stop execution from inside helper functions.
import{functionredirect(status:300|301|302|303|304|305|306|307|308|({}&number),location:string|URL):neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
@paramstatus TheHTTP status code. Must be in the range 300-308.@paramlocation The location to redirect to.@throwsRedirect This error instructs SvelteKit to redirect to the specified location.@throwsError If the provided status is invalid.redirect}from'@sveltejs/kit';/**@type{import('./$types').LayoutServerLoad}*/exportfunctionfunctionload(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>):MaybePromise<void|Record<string,any>>@type{import('./$types').LayoutServerLoad}load({locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals}) {if(!locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals.App.Locals.user?:{name:string;}|undefined
user) {functionredirect(status:300|301|302|303|304|305|306|307|308|({}&number),location:string|URL):neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
@paramstatus TheHTTP status code. Must be in the range 300-308.@paramlocation The location to redirect to.@throwsRedirect This error instructs SvelteKit to redirect to the specified location.@throwsError If the provided status is invalid.redirect(307,'/login');}}import{functionredirect(status:300|301|302|303|304|305|306|307|308|({}&number),location:string|URL):neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
@paramstatus TheHTTP status code. Must be in the range 300-308.@paramlocation The location to redirect to.@throwsRedirect This error instructs SvelteKit to redirect to the specified location.@throwsError If the provided status is invalid.redirect}from'@sveltejs/kit';importtype{typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad}from'./$types';exportconstconstload:LayoutServerLoadload:typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad=({locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals})=>{if(!locals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals.App.Locals.user?:{name:string;}|undefined
user) {functionredirect(status:300|301|302|303|304|305|306|307|308|({}&number),location:string|URL):neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
@paramstatus TheHTTP status code. Must be in the range 300-308.@paramlocation The location to redirect to.@throwsRedirect This error instructs SvelteKit to redirect to the specified location.@throwsError If the provided status is invalid.redirect(307,'/login');}};Don’t use
redirect()inside atry {...}block, as the redirect will immediately trigger the catch statement.
In the browser, you can also navigate programmatically outside of aload function usinggoto from$app.navigation.
In SvelteKit 1.x you had to
throwtheredirectyourself
Streaming with promises
When using a serverload, promises will be streamed to the browser as they resolve. This is useful if you have slow, non-essential data, since you can start rendering the page before all the data is available:
/**@type{import('./$types').PageServerLoad}*/exportasyncfunctionfunctionload(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>):MaybePromise<void|Record<string,any>>@type{import('./$types').PageServerLoad}load({params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params}) {return{// make sure the `await` happens at the end, otherwise we// can't start loading comments until we've loaded the postcomments:Promise<{content:string;}>
comments:constloadComments:(slug:string)=>Promise<{content:string;}>
loadComments(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug),post:{title:string;content:string;}
post:awaitconstloadPost:(slug:string)=>Promise<{title:string;content:string;}>
loadPost(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug)};}importtype{typePageServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>PageServerLoad}from'./$types';exportconstconstload:PageServerLoadload:typePageServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>PageServerLoad=async({params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params})=>{return{// make sure the `await` happens at the end, otherwise we// can't start loading comments until we've loaded the postcomments:Promise<{content:string;}>
comments:constloadComments:(slug:string)=>Promise<{content:string;}>
loadComments(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug),post:{title:string;content:string;}
post:awaitconstloadPost:(slug:string)=>Promise<{title:string;content:string;}>
loadPost(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug)};};This is useful for creating skeleton loading states, for example:
<script>/**@type{import('./$types').PageProps}*/let{ data }=$props();</script><h1>{data.post.title}</h1><div>{@htmldata.post.content}</div>{#awaitdata.comments}Loading comments...{:thencomments}{#eachcommentsascomment}<p>{comment.content}</p>{/each}{:catcherror}<p>error loading comments: {error.message}</p>{/await}<scriptlang="ts">importtype{ PageProps }from'./$types';let{ data }:PageProps=$props();</script><h1>{data.post.title}</h1><div>{@htmldata.post.content}</div>{#awaitdata.comments}Loading comments...{:thencomments}{#eachcommentsascomment}<p>{comment.content}</p>{/each}{:catcherror}<p>error loading comments: {error.message}</p>{/await}When streaming data, be careful to handle promise rejections correctly. More specifically, the server could crash with an “unhandled promise rejection” error if a lazy-loaded promise fails before rendering starts (at which point it’s caught) and isn’t handling the error in some way. When using SvelteKit’sfetch directly in theload function, SvelteKit will handle this case for you. For other promises, it is enough to attach a noop-catch to the promise to mark it as handled.
/**@type{import('./$types').PageServerLoad}*/exportfunctionfunctionload({ fetch }:{fetch:any;}):{ok_manual:Promise<never>;ok_fetch:any;dangerous_unhandled:Promise<never>;}
@type{import('./$types').PageServerLoad}load({fetch:anyfetch}) {constconstok_manual:Promise<never>ok_manual=varPromise:PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?:any):Promise<never>Creates a new rejected promise for the provided reason.
@paramreason The reason the promise was rejected.@returnsA new rejected Promise.reject();constok_manual:Promise<never>ok_manual.Promise<never>.catch<void>(onrejected?:((reason:any)=>void|PromiseLike<void>)|null|undefined):Promise<void>Attaches a callback for only the rejection of the Promise.
@paramonrejected The callback to execute when the Promise is rejected.@returnsA Promise for the completion of the callback.catch(()=>{});return{ok_manual:Promise<never>ok_manual,ok_fetch:anyok_fetch:fetch:anyfetch('/fetch/that/could/fail'),dangerous_unhandled:Promise<never>dangerous_unhandled:varPromise:PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?:any):Promise<never>Creates a new rejected promise for the provided reason.
@paramreason The reason the promise was rejected.@returnsA new rejected Promise.reject()};}importtype{typePageServerLoad=(event:Kit.ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageServerLoad=(event:Kit.ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageServerLoad}from'./$types';exportconstconstload:PageServerLoadload:typePageServerLoad=(event:Kit.ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageServerLoad=(event:Kit.ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageServerLoad=({fetch:{(input:RequestInfo|URL,init?:RequestInit):Promise<Response>;(input:string|URL|globalThis.Request,init?:RequestInit):Promise<Response>;}
fetch is equivalent to thenativefetch 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 directly 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 by hooking into the
text andjson methods of theResponse object. Note that headers willnot be serialized, unless explicitly included viafilterSerializedResponseHeaders - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookieshere.
fetch})=>{constconstok_manual:Promise<never>ok_manual=varPromise:PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?:any):Promise<never>Creates a new rejected promise for the provided reason.
@paramreason The reason the promise was rejected.@returnsA new rejected Promise.reject();constok_manual:Promise<never>ok_manual.Promise<never>.catch<void>(onrejected?:((reason:any)=>void|PromiseLike<void>)|null|undefined):Promise<void>Attaches a callback for only the rejection of the Promise.
@paramonrejected The callback to execute when the Promise is rejected.@returnsA Promise for the completion of the callback.catch(()=>{});return{ok_manual:Promise<never>ok_manual,ok_fetch:Promise<Response>ok_fetch:fetch:(input:string|URL|globalThis.Request,init?:RequestInit)=>Promise<Response> (+1overload)fetch('/fetch/that/could/fail'),dangerous_unhandled:Promise<never>dangerous_unhandled:varPromise:PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?:any):Promise<never>Creates a new rejected promise for the provided reason.
@paramreason The reason the promise was rejected.@returnsA new rejected Promise.reject()};};On platforms that do not support streaming, such as AWS Lambda or Firebase, responses will be buffered. This means the page will only render once all promises resolve. If you are using a proxy (e.g. NGINX), make sure it does not buffer responses from the proxied server.
Streaming data will only work when JavaScript is enabled. You should avoid returning promises from a universal
loadfunction if the page is server rendered, as these arenot streamed — instead, the promise is recreated when the function reruns in the browser.
The headers and status code of a response cannot be changed once the response has started streaming, therefore you cannot
setHeadersor throw redirects inside a streamed promise.
In SvelteKit 1.x top-level promises were automatically awaited, only nested promises were streamed.
Parallel loading
When rendering (or navigating to) a page, SvelteKit runs allload functions concurrently, avoiding a waterfall of requests. During client-side navigation, the result of calling multiple serverload functions are grouped into a single response. Once allload functions have returned, the page is rendered.
Rerunning load functions
SvelteKit tracks the dependencies of eachload function to avoid rerunning it unnecessarily during navigation.
For example, given a pair ofload functions like these...
import*asmodule"$lib/server/database"dbfrom'$lib/server/database';/**@type{import('./$types').PageServerLoad}*/exportasyncfunctionfunctionload(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>):MaybePromise<void|Record<string,any>>@type{import('./$types').PageServerLoad}load({params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params}) {return{post:{title:string;content:string;}
post:awaitmodule"$lib/server/database"db.functiongetPost(slug:string):Promise<{title:string;content:string;}>
getPost(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug)};}import*asmodule"$lib/server/database"dbfrom'$lib/server/database';importtype{typePageServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>PageServerLoad}from'./$types';exportconstconstload:PageServerLoadload:typePageServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>PageServerLoad=async({params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params})=>{return{post:{title:string;content:string;}
post:awaitmodule"$lib/server/database"db.functiongetPost(slug:string):Promise<{title:string;content:string;}>
getPost(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug)};};import*asmodule"$lib/server/database"dbfrom'$lib/server/database';/**@type{import('./$types').LayoutServerLoad}*/exportasyncfunctionfunctionload(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>):MaybePromise<void|Record<string,any>>@type{import('./$types').LayoutServerLoad}load() {return{posts:{title:string;slug:string;}[]
posts:awaitmodule"$lib/server/database"db.functiongetPostSummaries():Promise<Array<{title:string;slug:string;}>>
getPostSummaries()};}import*asmodule"$lib/server/database"dbfrom'$lib/server/database';importtype{typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad}from'./$types';exportconstconstload:LayoutServerLoadload:typeLayoutServerLoad=(event:ServerLoadEvent<Record<string,any>,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>LayoutServerLoad=async()=>{return{posts:{title:string;slug:string;}[]
posts:awaitmodule"$lib/server/database"db.functiongetPostSummaries():Promise<Array<{title:string;slug:string;}>>
getPostSummaries()};};...the one in+page.server.js will rerun if we navigate from/blog/trying-the-raw-meat-diet to/blog/i-regret-my-choices becauseparams.slug has changed. The one in+layout.server.js will not, because the data is still valid. In other words, we won’t calldb.getPostSummaries() a second time.
Aload function that callsawait parent() will also rerun if a parentload function is rerun.
Dependency tracking does not applyafter theload function has returned — for example, accessingparams.x inside a nestedpromise will not cause the function to rerun whenparams.x changes. (Don’t worry, you’ll get a warning in development if you accidentally do this.) Instead, access the parameter in the main body of yourload function.
Search parameters are tracked independently from the rest of the url. For example, accessingevent.url.searchParams.get("x") inside aload function will make thatload function re-run when navigating from?x=1 to?x=2, but not when navigating from?x=1&y=1 to?x=1&y=2.
Untracking dependencies
In rare cases, you may wish to exclude something from the dependency tracking mechanism. You can do this with the provideduntrack function:
/**@type{import('./$types').PageLoad}*/exportasyncfunctionfunctionload({ untrack,url }:{untrack:any;url:any;}):Promise<{message:string;}|undefined>
@type{import('./$types').PageLoad}load({untrack:anyuntrack,url:anyurl}) {// Untrack url.pathname so that path changes don't trigger a rerunif(untrack:anyuntrack(()=>url:anyurl.pathname==='/')) {return{message:stringmessage:'Welcome!'};}}importtype{typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad}from'./$types';exportconstconstload:PageLoadload:typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad=async({untrack:<T>(fn:()=>T)=>TUse this function to opt out of dependency tracking for everything that is synchronously called within the callback. Example:
src/routes/+page.serverexportasyncfunctionload({ untrack,url }) {// Untrack url.pathname so that path changes don't trigger a rerunif(untrack(()=>url.pathname==='/')) {return{ message:'Welcome!'};}}
untrack,url:URLThe URL of the current page
url})=>{// Untrack url.pathname so that path changes don't trigger a rerunif(untrack:<boolean>(fn:()=>boolean)=>booleanUse this function to opt out of dependency tracking for everything that is synchronously called within the callback. Example:
src/routes/+page.serverexportasyncfunctionload({ untrack,url }) {// Untrack url.pathname so that path changes don't trigger a rerunif(untrack(()=>url.pathname==='/')) {return{ message:'Welcome!'};}}
untrack(()=>url:URLThe URL of the current page
url.URL.pathname: stringpathname==='/')) {return{message:stringmessage:'Welcome!'};}};Manual invalidation
You can also rerunload functions that apply to the current page usinginvalidate(url), which reruns allload functions that depend onurl, andinvalidateAll(), which reruns everyload function. Server load functions will never automatically depend on a fetchedurl to avoid leaking secrets to the client.
Aload function depends onurl if it callsfetch(url) ordepends(url). Note thaturl can be a custom identifier that starts with[a-z]::
/**@type{import('./$types').PageLoad}*/exportasyncfunctionfunctionload({ fetch,depends }:{fetch:any;depends:any;}):Promise<{number:any;}>
@type{import('./$types').PageLoad}load({fetch:anyfetch,depends:anydepends}) {// load reruns when `invalidate('https://api.example.com/random-number')` is called...constconstresponse:anyresponse=awaitfetch:anyfetch('https://api.example.com/random-number');// ...or when `invalidate('app:random')` is calleddepends:anydepends('app:random');return{number:anynumber:awaitconstresponse:anyresponse.json()};}importtype{typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad}from'./$types';exportconstconstload:PageLoadload:typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>typePageLoad=(event:Kit.LoadEvent<Record<string,any>,Record<string,any>|null,Record<string,any>,string|null>)=>MaybePromise<void|Record<string,any>>
PageLoad=async({fetch:{(input:RequestInfo|URL,init?:RequestInit):Promise<Response>;(input:string|URL|globalThis.Request,init?:RequestInit):Promise<Response>;}
fetch is equivalent to thenativefetch 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 directly 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 by hooking into the
text andjson methods of theResponse object. Note that headers willnot be serialized, unless explicitly included viafilterSerializedResponseHeaders - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookieshere
fetch,depends:(...deps:Array<`${string}:${string}`>)=>voidThis function declares that theload function has adependency on one or more URLs or custom identifiers, which can subsequently be used withinvalidate() to causeload to rerun.
Most of the time you won’t need this, asfetch callsdepends on your behalf — it’s only necessary if you’re using a custom API client that bypassesfetch.
URLs can be absolute or relative to the page being loaded, and must beencoded.
Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to theURI specification.
The following example shows how to usedepends to register a dependency on a custom identifier, which isinvalidated after a button click, making theload function rerun.
src/routes/+pageletcount=0;exportasyncfunctionload({ depends }) {depends('increase:count');return{ count:count++};}
src/routes/+page<script>import { invalidate } from '$app/navigation';let { data } = $props();const increase = async () => {awaitinvalidate('increase:count');}</script><p>{data.count}<p><button on:click={increase}>Increase Count</button>
depends})=>{// load reruns when `invalidate('https://api.example.com/random-number')` is called...constconstresponse:Responseresponse=awaitfetch:(input:string|URL|globalThis.Request,init?:RequestInit)=>Promise<Response> (+1overload)fetch('https://api.example.com/random-number');// ...or when `invalidate('app:random')` is calleddepends:(...deps:Array<`${string}:${string}`>)=>voidThis function declares that theload function has adependency on one or more URLs or custom identifiers, which can subsequently be used withinvalidate() to causeload to rerun.
Most of the time you won’t need this, asfetch callsdepends on your behalf — it’s only necessary if you’re using a custom API client that bypassesfetch.
URLs can be absolute or relative to the page being loaded, and must beencoded.
Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to theURI specification.
The following example shows how to usedepends to register a dependency on a custom identifier, which isinvalidated after a button click, making theload function rerun.
src/routes/+pageletcount=0;exportasyncfunctionload({ depends }) {depends('increase:count');return{ count:count++};}
src/routes/+page<script>import { invalidate } from '$app/navigation';let { data } = $props();const increase = async () => {awaitinvalidate('increase:count');}</script><p>{data.count}<p><button on:click={increase}>Increase Count</button>
depends('app:random');return{number:anynumber:awaitconstresponse:Responseresponse.Body.json():Promise<any>json()};};<script>import{ invalidate,invalidateAll }from'$app/navigation';/**@type{import('./$types').PageProps}*/let{ data }=$props();functionrerunLoadFunction() {// any of these will cause the `load` function to reruninvalidate('app:random');invalidate('https://api.example.com/random-number');invalidate(url=>url.href.includes('random-number'));invalidateAll();}</script><p>random number: {data.number}</p><buttononclick={rerunLoadFunction}>Update random number</button><scriptlang="ts">import{ invalidate,invalidateAll }from'$app/navigation';importtype{ PageProps }from'./$types';let{ data }:PageProps=$props();functionrerunLoadFunction() {// any of these will cause the `load` function to reruninvalidate('app:random');invalidate('https://api.example.com/random-number');invalidate(url=>url.href.includes('random-number'));invalidateAll();}</script><p>random number: {data.number}</p><buttononclick={rerunLoadFunction}>Update random number</button>When do load functions rerun?
To summarize, aload function will rerun in the following situations:
- It references a property of
paramswhose value has changed - It references a property of
url(such asurl.pathnameorurl.search) whose value has changed. Properties inrequest.urlarenot tracked - It calls
url.searchParams.get(...),url.searchParams.getAll(...)orurl.searchParams.has(...)and the parameter in question changes. Accessing other properties ofurl.searchParamswill have the same effect as accessingurl.search. - It calls
await parent()and a parentloadfunction reran - A child
loadfunction callsawait parent()and is rerunning, and the parent is a server load function - It declared a dependency on a specific URL via
fetch(universal load only) ordepends, and that URL was marked invalid withinvalidate(url) - All active
loadfunctions were forcibly rerun withinvalidateAll()
params andurl can change in response to a<a href=".."> link click, a<form> interaction, agoto invocation, or aredirect.
Note that rerunning aload function will update thedata prop inside the corresponding+layout.svelte or+page.svelte; it doesnot cause the component to be recreated. As a result, internal state is preserved. If this isn’t what you want, you can reset whatever you need to reset inside anafterNavigate callback, and/or wrap your component in a{#key ...} block.
Implications for authentication
A couple features of loading data have important implications for auth checks:
- Layout
loadfunctions do not run on every request, such as during client side navigation between child routes.(When do load functions rerun?) - Layout and page
loadfunctions run concurrently unlessawait parent()is called. If a layoutloadthrows, the pageloadfunction runs, but the client will not receive the returned data.
There are a few possible strategies to ensure an auth check occurs before protected code.
To prevent data waterfalls and preserve layoutload caches:
- Usehooks to protect multiple routes before any
loadfunctions run - Use auth guards directly in
+page.server.jsloadfunctions for route specific protection
Putting an auth guard in+layout.server.js requires all child pages to callawait parent() before protected code. Unless every child page depends on returned data fromawait parent(), the other options will be more performant.
Using getRequestEvent
When running serverload functions, theevent object passed to the function as an argument can also be retrieved withgetRequestEvent. This allows shared logic (such as authentication guards) to access information about the current request without it needing to be passed around.
For example, you might have a function that requires users to be logged in, and redirects them to/login if not:
import{functionredirect(status:300|301|302|303|304|305|306|307|308|({}&number),location:string|URL):neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
@paramstatus TheHTTP status code. Must be in the range 300-308.@paramlocation The location to redirect to.@throwsRedirect This error instructs SvelteKit to redirect to the specified location.@throwsError If the provided status is invalid.redirect}from'@sveltejs/kit';import{functiongetRequestEvent():RequestEventReturns the currentRequestEvent. Can be used inside server hooks, serverload functions, actions, and endpoints (and functions called by them).
In environments withoutAsyncLocalStorage, this must be called synchronously (i.e. not after anawait).
@since2.20.0getRequestEvent}from'$app/server';exportfunctionfunctionrequireLogin():UserrequireLogin() {const{constlocals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals,consturl:URLThe requested URL.
url}=functiongetRequestEvent():RequestEventReturns the currentRequestEvent. Can be used inside server hooks, serverload functions, actions, and endpoints (and functions called by them).
In environments withoutAsyncLocalStorage, this must be called synchronously (i.e. not after anawait).
@since2.20.0getRequestEvent();// assume `locals.user` is populated in `handle`if(!constlocals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals.App.Locals.user?:User|undefineduser) {constconstredirectTo:stringredirectTo=consturl:URLThe requested URL.
url.URL.pathname: stringpathname+consturl:URLThe requested URL.
url.URL.search: stringsearch;constconstparams:URLSearchParamsparams=newvarURLSearchParams:new(init?:string[][]|Record<string,string>|string|URLSearchParams)=>URLSearchParamsURLSearchParams class is a global reference forimport { URLSearchParams } from 'node:url'https://nodejs.org/api/url.html#class-urlsearchparams
@sincev10.0.0URLSearchParams({redirectTo:stringredirectTo});functionredirect(status:300|301|302|303|304|305|306|307|308|({}&number),location:string|URL):neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other: redirect as a GET request (often used after a form POST request)307 Temporary Redirect: redirect will keep the request method308 Permanent Redirect: redirect will keep the request method, SEO will be transferred to the new page
@paramstatus TheHTTP status code. Must be in the range 300-308.@paramlocation The location to redirect to.@throwsRedirect This error instructs SvelteKit to redirect to the specified location.@throwsError If the provided status is invalid.redirect(307,`/login?${constparams:URLSearchParamsparams}`);}returnconstlocals:App.LocalsContains custom data that was added to the request within theserver handle hook.
locals.App.Locals.user?:Useruser;}Now, you can callrequireLogin in anyload function (orform action, for example) to guarantee that the user is logged in:
import{functionrequireLogin():UserrequireLogin}from'$lib/server/auth';exportfunctionfunctionload():{message:string;}
load() {constconstuser:Useruser=functionrequireLogin():UserrequireLogin();// `user` is guaranteed to be a user object here, because otherwise// `requireLogin` would throw a redirect and we wouldn't get herereturn{message:stringmessage:`hello${constuser:Useruser.User.name: stringname}!`};}Further reading
Edit this page on GitHub llms.txt