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
Routing
At the heart of SvelteKit is afilesystem-based router. The routes of your app — i.e. the URL paths that users can access — are defined by the directories in your codebase:
src/routesis the root routesrc/routes/aboutcreates an/aboutroutesrc/routes/blog/[slug]creates a route with aparameter,slug, that can be used to load data dynamically when a user requests a page like/blog/hello-world
You can change
src/routesto a different directory by editing theproject config.
Each route directory contains one or moreroute files, which can be identified by their+ prefix.
We’ll introduce these files in a moment in more detail, but here are a few simple rules to help you remember how SvelteKit’s routing works:
- All files can run on the server
- All files run on the client except
+serverfiles +layoutand+errorfiles apply to subdirectories as well as the directory they live in
+page
+page.svelte
A+page.svelte component defines a page of your app. By default, pages are rendered both on the server (SSR) for the initial request and in the browser (CSR) for subsequent navigation.
<h1>Hello and welcome to my site!</h1><ahref="/about">About my site</a><h1>About this site</h1><p>TODO...</p><ahref="/">Home</a>SvelteKit uses
<a>elements to navigate between routes, rather than a framework-specific<Link>component.
Pages can receive data fromload functions via thedata prop.
<script>/**@type{import('./$types').PageProps}*/let{ data }=$props();</script><h1>{data.title}</h1><div>{@htmldata.content}</div><scriptlang="ts">importtype{ PageProps }from'./$types';let{ data }:PageProps=$props();</script><h1>{data.title}</h1><div>{@htmldata.content}</div>Legacy mode
PagePropswas added in 2.16.0. In earlier versions, you had to type thedataproperty manually withPageDatainstead, see$types.In Svelte 4, you’d use
export let datainstead.
+page.js
Often, a page will need to load some data before it can be rendered. For this, we add a+page.js module that exports aload function:
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').PageLoad}*/exportfunctionfunctionload({ params }:{params:any;}):{title:string;content:string;}
@type{import('./$types').PageLoad}load({params:anyparams}) {if(params:anyparams.slug==='hello-world') {return{title:stringtitle:'Hello world!',content:stringcontent:'Welcome to our blog. Lorem ipsum dolor sit amet...'};}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(404,'Not found');}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{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})=>{if(params:Record<string,any>The parameters of the current page - e.g. for a route like/blog/[slug], a{ slug: string } object
params.slug==='hello-world') {return{title:stringtitle:'Hello world!',content:stringcontent:'Welcome to our blog. Lorem ipsum dolor sit amet...'};}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(404,'Not found');};This function runs alongside+page.svelte, which means it runs on the server during server-side rendering and in the browser during client-side navigation. Seeload for full details of the API.
As well asload,+page.js can export values that configure the page’s behaviour:
export const prerender = trueorfalseor'auto'export const ssr = trueorfalseexport const csr = trueorfalse
You can find more information about these inpage options.
+page.server.js
If yourload function can only run on the server — for example, if it needs to fetch data from a database or you need to access privateenvironment variables like API keys — then you can rename+page.js to+page.server.js and change thePageLoad type toPageServerLoad.
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').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}) {constconstpost:{title:string;content:string;}
post=awaitconstgetPostFromDatabase:(slug:string)=>{title:string;content:string;}
getPostFromDatabase(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug);if(constpost:{title:string;content:string;}
post) {returnconstpost:{title:string;content:string;}
post;}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(404,'Not found');}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{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})=>{constconstpost:{title:string;content:string;}
post=awaitconstgetPostFromDatabase:(slug:string)=>{title:string;content:string;}
getPostFromDatabase(params:Record<string,any>The parameters of the current route - e.g. for a route like/blog/[slug], a{ slug: string } object.
params.slug);if(constpost:{title:string;content:string;}
post) {returnconstpost:{title:string;content:string;}
post;}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(404,'Not found');};During client-side navigation, SvelteKit will load this data from the server, which means that the returned value must be serializable usingdevalue. Seeload for full details of the API.
Like+page.js,+page.server.js can exportpage options —prerender,ssr andcsr.
A+page.server.js file can also exportactions. Ifload lets you read data from the server,actions let you write datato the server using the<form> element. To learn how to use them, see theform actions section.
+error
If an error occurs duringload, SvelteKit will render a default error page. You can customise this error page on a per-route basis by adding an+error.svelte file:
<script>import{ page }from'$app/state';</script><h1>{page.status}: {page.error.message}</h1><scriptlang="ts">import{ page }from'$app/state';</script><h1>{page.status}: {page.error.message}</h1>Legacy mode
$app/statewas added in SvelteKit 2.12. If you’re using an earlier version or are using Svelte 4, use$app/storesinstead.
SvelteKit will ‘walk up the tree’ looking for the closest error boundary — if the file above didn’t exist it would trysrc/routes/blog/+error.svelte and thensrc/routes/+error.svelte before rendering the default error page. Ifthat fails (or if the error was thrown from theload function of the root+layout, which sits ‘above’ the root+error), SvelteKit will bail out and render a static fallback error page, which you can customise by creating asrc/error.html file.
If the error occurs inside aload function in+layout(.server).js, the closest error boundary in the tree is an+error.svelte fileabove that layout (not next to it).
If no route can be found (404),src/routes/+error.svelte (or the default error page, if that file does not exist) will be used.
+error.svelteisnot used when an error occurs insidehandleor a+server.js request handler.
You can read more about error handlinghere.
+layout
So far, we’ve treated pages as entirely standalone components — upon navigation, the existing+page.svelte component will be destroyed, and a new one will take its place.
But in many apps, there are elements that should be visible onevery page, such as top-level navigation or a footer. Instead of repeating them in every+page.svelte, we can put them inlayouts.
+layout.svelte
To create a layout that applies to every page, make a file calledsrc/routes/+layout.svelte. The default layout (the one that SvelteKit uses if you don’t bring your own) looks like this...
<script>let{ children }=$props();</script>{@renderchildren()}...but we can add whatever markup, styles and behaviour we want. The only requirement is that the component includes a@render tag for the page content. For example, let’s add a nav bar:
<script>let{ children }=$props();</script><nav><ahref="/">Home</a><ahref="/about">About</a><ahref="/settings">Settings</a></nav>{@renderchildren()}<scriptlang="ts">let{ children }=$props();</script><nav><ahref="/">Home</a><ahref="/about">About</a><ahref="/settings">Settings</a></nav>{@renderchildren()}If we create pages for/,/about and/settings...
<h1>Home</h1><h1>About</h1><h1>Settings</h1>...the nav will always be visible, and clicking between the three pages will only result in the<h1> being replaced.
Layouts can benested. Suppose we don’t just have a single/settings page, but instead have nested pages like/settings/profile and/settings/notifications with a shared submenu (for a real-life example, seegithub.com/settings).
We can create a layout that only applies to pages below/settings (while inheriting the root layout with the top-level nav):
<script>/**@type{import('./$types').LayoutProps}*/let{ data,children }=$props();</script><h1>Settings</h1><divclass="submenu">{#eachdata.sectionsassection}<ahref="/settings/{section.slug}">{section.title}</a>{/each}</div>{@renderchildren()}<scriptlang="ts">importtype{ LayoutProps }from'./$types';let{ data,children }:LayoutProps=$props();</script><h1>Settings</h1><divclass="submenu">{#eachdata.sectionsassection}<ahref="/settings/{section.slug}">{section.title}</a>{/each}</div>{@renderchildren()}Legacy mode
LayoutPropswas added in 2.16.0. In earlier versions, you had totype the properties manually instead.
You can see howdata is populated by looking at the+layout.js example in the next section just below.
By default, each layout inherits the layout above it. Sometimes that isn’t what you want - in this case,advanced layouts can help you.
+layout.js
Just like+page.svelte loading data from+page.js, your+layout.svelte component can get data from aload function in+layout.js.
/**@type{import('./$types').LayoutLoad}*/exportfunctionfunctionload():{sections:{slug:string;title:string;}[];}
@type{import('./$types').LayoutLoad}load() {return{sections:{slug:string;title:string;}[]
sections:[{slug:stringslug:'profile',title:stringtitle:'Profile'},{slug:stringslug:'notifications',title:stringtitle:'Notifications'}]};}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{sections:{slug:string;title:string;}[]
sections:[{slug:stringslug:'profile',title:stringtitle:'Profile'},{slug:stringslug:'notifications',title:stringtitle:'Notifications'}]};};If a+layout.js exportspage options —prerender,ssr andcsr — they will be used as defaults for child pages.
Data returned from a layout’sload function is also available to all its child pages:
<script>/**@type{import('./$types').PageProps}*/let{ data }=$props();console.log(data.sections);// [{ slug: 'profile', title: 'Profile' }, ...]</script><scriptlang="ts">importtype{ PageProps }from'./$types';let{ data }:PageProps=$props();console.log(data.sections);// [{ slug: 'profile', title: 'Profile' }, ...]</script>Often, layout data is unchanged when navigating between pages. SvelteKit will intelligently rerun
loadfunctions when necessary.
+layout.server.js
To run your layout’sload function on the server, move it to+layout.server.js, and change theLayoutLoad type toLayoutServerLoad.
Like+layout.js,+layout.server.js can exportpage options —prerender,ssr andcsr.
+server
As well as pages, you can define routes with a+server.js file (sometimes referred to as an ‘API route’ or an ‘endpoint’), which gives you full control over the response. Your+server.js file exports functions corresponding to HTTP verbs likeGET,POST,PATCH,PUT,DELETE,OPTIONS, andHEAD that take aRequestEvent argument and return aResponse object.
For example we could create an/api/random-number route with aGET handler:
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').RequestHandler}*/exportfunctionfunctionGET({ url }:{url:any;}):Response
@type{import('./$types').RequestHandler}GET({url:anyurl}) {constconstmin:numbermin=varNumber:NumberConstructor(value?:any)=>number
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number(url:anyurl.searchParams.get('min')??'0');constconstmax:numbermax=varNumber:NumberConstructor(value?:any)=>number
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number(url:anyurl.searchParams.get('max')??'1');constconstd:numberd=constmax:numbermax-constmin:numbermin;if(functionisNaN(number:number):booleanReturns a Boolean value that indicates whether a value is the reserved value NaN (not a number).
@paramnumber A numeric value.isNaN(constd:numberd)||constd:numberd<0) {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(400,'min and max must be numbers, and min must be less than max');}constconstrandom:numberrandom=constmin:numbermin+varMath:MathAn intrinsic object that provides basic mathematics functionality and constants.
Math.Math.random(): numberReturns a pseudorandom number between 0 and 1.
random()*constd:numberd;returnnewvarResponse:new(body?:BodyInit|null,init?:ResponseInit)=>ResponseThis Fetch API interface represents the response to a request.
Response(varString:StringConstructor(value?:any)=>string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(constrandom:numberrandom));}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{typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>
RequestHandler}from'./$types';exportconstconstGET:RequestHandlerGET:typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>
RequestHandler=({url:URLThe requested URL.
url})=>{constconstmin:numbermin=varNumber:NumberConstructor(value?:any)=>number
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number(url:URLThe requested URL.
url.URL.searchParams: URLSearchParamssearchParams.URLSearchParams.get(name: string): string|nullReturns the first value associated to the given search parameter.
get('min')??'0');constconstmax:numbermax=varNumber:NumberConstructor(value?:any)=>number
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number(url:URLThe requested URL.
url.URL.searchParams: URLSearchParamssearchParams.URLSearchParams.get(name: string): string|nullReturns the first value associated to the given search parameter.
get('max')??'1');constconstd:numberd=constmax:numbermax-constmin:numbermin;if(functionisNaN(number:number):booleanReturns a Boolean value that indicates whether a value is the reserved value NaN (not a number).
@paramnumber A numeric value.isNaN(constd:numberd)||constd:numberd<0) {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(400,'min and max must be numbers, and min must be less than max');}constconstrandom:numberrandom=constmin:numbermin+varMath:MathAn intrinsic object that provides basic mathematics functionality and constants.
Math.Math.random(): numberReturns a pseudorandom number between 0 and 1.
random()*constd:numberd;returnnewvarResponse:new(body?:BodyInit|null,init?:ResponseInit)=>ResponseThis Fetch API interface represents the response to a request.
Response(varString:StringConstructor(value?:any)=>string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(constrandom:numberrandom));};The first argument toResponse can be aReadableStream, making it possible to stream large amounts of data or create server-sent events (unless deploying to platforms that buffer responses, like AWS Lambda).
You can use theerror,redirect andjson methods from@sveltejs/kit for convenience (but you don’t have to).
If an error is thrown (eithererror(...) or an unexpected error), the response will be a JSON representation of the error or a fallback error page — which can be customised viasrc/error.html — depending on theAccept header. The+error.svelte component willnot be rendered in this case. You can read more about error handlinghere.
When creating an
OPTIONShandler, note that Vite will injectAccess-Control-Allow-OriginandAccess-Control-Allow-Methodsheaders — these will not be present in production unless you add them.
+layoutfiles have no effect on+server.jsfiles. If you want to run some logic before each request, add it to the serverhandlehook.
Receiving data
By exportingPOST /PUT/PATCH/DELETE/OPTIONS/HEAD handlers,+server.js files can be used to create a complete API:
<script>leta=0;letb=0;lettotal=0;asyncfunctionadd() {constresponse=awaitfetch('/api/add',{method:'POST',body:JSON.stringify({ a,b }),headers:{'content-type':'application/json'}});total=awaitresponse.json();}</script><inputtype="number"bind:value={a}> +<inputtype="number"bind:value={b}> ={total}<buttononclick={add}>Calculate</button><scriptlang="ts">leta=0;letb=0;lettotal=0;asyncfunctionadd() {constresponse=awaitfetch('/api/add',{method:'POST',body:JSON.stringify({ a,b }),headers:{'content-type':'application/json'}});total=awaitresponse.json();}</script><inputtype="number"bind:value={a}> +<inputtype="number"bind:value={b}> ={total}<buttononclick={add}>Calculate</button>import{functionjson(data:any,init?:ResponseInit):ResponseCreate a JSONResponse object from the supplied data.
@paramdata The value that will be serialized as JSON.@paraminit Options such asstatus andheaders that will be added to the response.Content-Type: application/json andContent-Length headers will be added automatically.json}from'@sveltejs/kit';/**@type{import('./$types').RequestHandler}*/exportasyncfunctionfunctionPOST({ request }:{request:any;}):Promise<Response>
@type{import('./$types').RequestHandler}POST({request:anyrequest}) {const{consta:anya,constb:anyb}=awaitrequest:anyrequest.json();returnfunctionjson(data:any,init?:ResponseInit):ResponseCreate a JSONResponse object from the supplied data.
@paramdata The value that will be serialized as JSON.@paraminit Options such asstatus andheaders that will be added to the response.Content-Type: application/json andContent-Length headers will be added automatically.json(consta:anya+constb:anyb);}import{functionjson(data:any,init?:ResponseInit):ResponseCreate a JSONResponse object from the supplied data.
@paramdata The value that will be serialized as JSON.@paraminit Options such asstatus andheaders that will be added to the response.Content-Type: application/json andContent-Length headers will be added automatically.json}from'@sveltejs/kit';importtype{typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>
RequestHandler}from'./$types';exportconstconstPOST:RequestHandlerPOST:typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>
RequestHandler=async({request:RequestThe original request object.
request})=>{const{consta:anya,constb:anyb}=awaitrequest:RequestThe original request object.
request.Body.json():Promise<any>json();returnfunctionjson(data:any,init?:ResponseInit):ResponseCreate a JSONResponse object from the supplied data.
@paramdata The value that will be serialized as JSON.@paraminit Options such asstatus andheaders that will be added to the response.Content-Type: application/json andContent-Length headers will be added automatically.json(consta:anya+constb:anyb);};In general,form actions are a better way to submit data from the browser to the server.
If a
GEThandler is exported, aHEADrequest will return thecontent-lengthof theGEThandler’s response body.
Fallback method handler
Exporting thefallback handler will match any unhandled request methods, including methods likeMOVE which have no dedicated export from+server.js.
import{functionjson(data:any,init?:ResponseInit):ResponseCreate a JSONResponse object from the supplied data.
@paramdata The value that will be serialized as JSON.@paraminit Options such asstatus andheaders that will be added to the response.Content-Type: application/json andContent-Length headers will be added automatically.json,functiontext(body:string,init?:ResponseInit):ResponseCreate aResponse object from the supplied body.
@parambody The value that will be used as-is.@paraminit Options such asstatus andheaders that will be added to the response. AContent-Length header will be added automatically.text}from'@sveltejs/kit';/**@type{import('./$types').RequestHandler}*/exportasyncfunctionfunctionPOST({ request }:{request:any;}):Promise<Response>
@type{import('./$types').RequestHandler}POST({request:anyrequest}) {const{consta:anya,constb:anyb}=awaitrequest:anyrequest.json();returnfunctionjson(data:any,init?:ResponseInit):ResponseCreate a JSONResponse object from the supplied data.
@paramdata The value that will be serialized as JSON.@paraminit Options such asstatus andheaders that will be added to the response.Content-Type: application/json andContent-Length headers will be added automatically.json(consta:anya+constb:anyb);}// This handler will respond to PUT, PATCH, DELETE, etc./**@type{import('./$types').RequestHandler}*/exportasyncfunctionfunctionfallback({ request }:{request:any;}):Promise<Response>
@type{import('./$types').RequestHandler}fallback({request:anyrequest}) {returnfunctiontext(body:string,init?:ResponseInit):ResponseCreate aResponse object from the supplied body.
@parambody The value that will be used as-is.@paraminit Options such asstatus andheaders that will be added to the response. AContent-Length header will be added automatically.text(`I caught your${request:anyrequest.method}request!`);}import{functionjson(data:any,init?:ResponseInit):ResponseCreate a JSONResponse object from the supplied data.
@paramdata The value that will be serialized as JSON.@paraminit Options such asstatus andheaders that will be added to the response.Content-Type: application/json andContent-Length headers will be added automatically.json,functiontext(body:string,init?:ResponseInit):ResponseCreate aResponse object from the supplied body.
@parambody The value that will be used as-is.@paraminit Options such asstatus andheaders that will be added to the response. AContent-Length header will be added automatically.text}from'@sveltejs/kit';importtype{typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>
RequestHandler}from'./$types';exportconstconstPOST:RequestHandlerPOST:typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>
RequestHandler=async({request:RequestThe original request object.
request})=>{const{consta:anya,constb:anyb}=awaitrequest:RequestThe original request object.
request.Body.json():Promise<any>json();returnfunctionjson(data:any,init?:ResponseInit):ResponseCreate a JSONResponse object from the supplied data.
@paramdata The value that will be serialized as JSON.@paraminit Options such asstatus andheaders that will be added to the response.Content-Type: application/json andContent-Length headers will be added automatically.json(consta:anya+constb:anyb);};// This handler will respond to PUT, PATCH, DELETE, etc.exportconstconstfallback:RequestHandlerfallback:typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>typeRequestHandler=(event:Kit.RequestEvent<Record<string,any>,string|null>)=>MaybePromise<Response>
RequestHandler=async({request:RequestThe original request object.
request})=>{returnfunctiontext(body:string,init?:ResponseInit):ResponseCreate aResponse object from the supplied body.
@parambody The value that will be used as-is.@paraminit Options such asstatus andheaders that will be added to the response. AContent-Length header will be added automatically.text(`I caught your${request:RequestThe original request object.
request.Request.method: stringReturns request’s HTTP method, which is “GET” by default.
method}request!`);};For
HEADrequests, theGEThandler takes precedence over thefallbackhandler.
Content negotiation
+server.js files can be placed in the same directory as+page files, allowing the same route to be either a page or an API endpoint. To determine which, SvelteKit applies the following rules:
PUT/PATCH/DELETE/OPTIONSrequests are always handled by+server.jssince they do not apply to pagesGET/POST/HEADrequests are treated as page requests if theacceptheader prioritisestext/html(in other words, it’s a browser page request), else they are handled by+server.js.- Responses to
GETrequests will include aVary: Acceptheader, so that proxies and browsers cache HTML and JSON responses separately.
$types
Throughout the examples above, we’ve been importing types from a$types.d.ts file. This is a file SvelteKit creates for you in a hidden directory if you’re using TypeScript (or JavaScript with JSDoc type annotations) to give you type safety when working with your root files.
For example, annotatinglet { data } = $props() withPageProps (orLayoutProps, for a+layout.svelte file) tells TypeScript that the type ofdata is whatever was returned fromload:
<script>/**@type{import('./$types').PageProps}*/let{ data }=$props();</script><scriptlang="ts">importtype{ PageProps }from'./$types';let{ data }:PageProps=$props();</script>The
PagePropsandLayoutPropstypes, added in 2.16.0, are a shortcut for typing thedataprop asPageDataorLayoutData, as well as other props, such asformfor pages, orchildrenfor layouts. In earlier versions, you had to type these properties manually. For example, for a page:+page/**@type{{ data: import('./$types').PageData, form: import('./$types').ActionData }}*/let{letdata:anydata,letform:anyform}=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,importActionDataActionData}from'./$types';let{letdata:PageDatadata,letform:ActionDataform}:{data:PageDatadata:importPageDataPageData,form:ActionDataform:importActionDataActionData}=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();Or, for a layout:
+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();
In turn, annotating theload function withPageLoad,PageServerLoad,LayoutLoad orLayoutServerLoad (for+page.js,+page.server.js,+layout.js and+layout.server.js respectively) ensures thatparams and the return value are correctly typed.
If you’re using VS Code or any IDE that supports the language server protocol and TypeScript plugins then you can omit these typesentirely! Svelte’s IDE tooling will insert the correct types for you, so you’ll get type checking without writing them yourself. It also works with our command line toolsvelte-check.
You can read more about omitting$types in ourblog post about it.
Other files
Any other files inside a route directory are ignored by SvelteKit. This means you can colocate components and utility modules with the routes that need them.
If components and modules are needed by multiple routes, it’s a good idea to put them in$lib.
Further reading
Edit this page on GitHub llms.txt