Build and deploy
Node servers
Edit this page on GitHubTo generate a standalone Node server, use adapter-node
.
Usagepermalink
Install with npm i -D @sveltejs/adapter-node
, then add the adapter to your svelte.config.js
:
ts
importCannot find module '@sveltejs/adapter-node' or its corresponding type declarations.2307Cannot find module '@sveltejs/adapter-node' or its corresponding type declarations.adapter from'@sveltejs/adapter-node' ;export default {kit : {adapter :adapter ()}};
Deployingpermalink
First, build your app with npm run build
. This will create the production server in the output directory specified in the adapter options, defaulting to build
.
You will need the output directory, the project's package.json
, and the production dependencies in node_modules
to run the application. Production dependencies can be generated by copying the package.json
and package-lock.json
and then running npm ci --omit dev
(you can skip this step if your app doesn't have any dependencies). You can then start your app with this command:
node build
Development dependencies will be bundled into your app using Rollup. To control whether a given package is bundled or externalised, place it in devDependencies
or dependencies
respectively in your package.json
.
Environment variablespermalink
In dev
and preview
, SvelteKit will read environment variables from your .env
file (or .env.local
, or .env.[mode]
, as determined by Vite.)
In production, .env
files are not automatically loaded. To do so, install dotenv
in your project...
npm install dotenv
...and invoke it before running the built app:
node build
node -r dotenv/config build
PORT and HOSTpermalink
By default, the server will accept connections on 0.0.0.0
using port 3000. These can be customised with the PORT
and HOST
environment variables:
HOST=127.0.0.1 PORT=4000 node build
ORIGIN, PROTOCOL_HEADER and HOST_HEADERpermalink
HTTP doesn't give SvelteKit a reliable way to know the URL that is currently being requested. The simplest way to tell SvelteKit where the app is being served is to set the ORIGIN
environment variable:
ORIGIN=https://my.site node build
# or e.g. for local previewing and testing
ORIGIN=http://localhost:3000 node build
With this, a request for the /stuff
pathname will correctly resolve to https://my.site/stuff
. Alternatively, you can specify headers that tell SvelteKit about the request protocol and host, from which it can construct the origin URL:
PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host node build
x-forwarded-proto
andx-forwarded-host
are de facto standard headers that forward the original protocol and host if you're using a reverse proxy (think load balancers and CDNs). You should only set these variables if your server is behind a trusted reverse proxy; otherwise, it'd be possible for clients to spoof these headers.
If adapter-node
can't correctly determine the URL of your deployment, you may experience this error when using form actions:
Cross-site POST form submissions are forbidden
ADDRESS_HEADER and XFF_DEPTHpermalink
The RequestEvent object passed to hooks and endpoints includes an event.getClientAddress()
function that returns the client's IP address. By default this is the connecting remoteAddress
. If your server is behind one or more proxies (such as a load balancer), this value will contain the innermost proxy's IP address rather than the client's, so we need to specify an ADDRESS_HEADER
to read the address from:
ADDRESS_HEADER=True-Client-IP node build
Headers can easily be spoofed. As with
PROTOCOL_HEADER
andHOST_HEADER
, you should know what you're doing before setting these.
If the ADDRESS_HEADER
is X-Forwarded-For
, the header value will contain a comma-separated list of IP addresses. The XFF_DEPTH
environment variable should specify how many trusted proxies sit in front of your server. E.g. if there are three trusted proxies, proxy 3 will forward the addresses of the original connection and the first two proxies:
<client address>, <proxy 1 address>, <proxy 2 address>
Some guides will tell you to read the left-most address, but this leaves you vulnerable to spoofing:
<spoofed address>, <client address>, <proxy 1 address>, <proxy 2 address>
We instead read from the right, accounting for the number of trusted proxies. In this case, we would use XFF_DEPTH=3
.
If you need to read the left-most address instead (and don't care about spoofing) — for example, to offer a geolocation service, where it's more important for the IP address to be real than trusted, you can do so by inspecting the
x-forwarded-for
header within your app.
BODY_SIZE_LIMITpermalink
The maximum request body size to accept in bytes including while streaming. Defaults to 512kb. You can disable this option with a value of 0 and implement a custom check in handle
if you need something more advanced.
Optionspermalink
The adapter can be configured with various options:
ts
importCannot find module '@sveltejs/adapter-node' or its corresponding type declarations.2307Cannot find module '@sveltejs/adapter-node' or its corresponding type declarations.adapter from'@sveltejs/adapter-node' ;export default {kit : {adapter :adapter ({// default options are shownout : 'build',precompress : false,envPrefix : '',polyfill : true})}};
outpermalink
The directory to build the server to. It defaults to build
— i.e. node build
would start the server locally after it has been created.
precompresspermalink
Enables precompressing using gzip and brotli for assets and prerendered pages. It defaults to false
.
envPrefixpermalink
If you need to change the name of the environment variables used to configure the deployment (for example, to deconflict with environment variables you don't control), you can specify a prefix:
ts
envPrefix: 'MY_CUSTOM_';
MY_CUSTOM_HOST=127.0.0.1 \
MY_CUSTOM_PORT=4000 \
MY_CUSTOM_ORIGIN=https://my.site \
node build
polyfillpermalink
Controls whether your build will load polyfills for missing modules. It defaults to true
, and should only be disabled when using Node 18.11 or greater.
Note: to use Node's built-in crypto
global with Node 18 you will need to use the --experimental-global-webcrypto
flag. This flag is not required with Node 20.
Custom serverpermalink
The adapter creates two files in your build directory — index.js
and handler.js
. Running index.js
— e.g. node build
, if you use the default build directory — will start a server on the configured port.
Alternatively, you can import the handler.js
file, which exports a handler suitable for use with Express, Connect or Polka (or even just the built-in http.createServer
) and set up your own server:
ts
import {Cannot find module './build/handler.js' or its corresponding type declarations.2307Cannot find module './build/handler.js' or its corresponding type declarations.handler } from'./build/handler.js' ;importCannot find module 'express' or its corresponding type declarations.2307Cannot find module 'express' or its corresponding type declarations.express from'express' ;constapp =express ();// add a route that lives separately from the SvelteKit appParameter 'req' implicitly has an 'any' type.Parameter 'res' implicitly has an 'any' type.7006app .get ('/healthcheck', (, req ) => { res
7006Parameter 'req' implicitly has an 'any' type.Parameter 'res' implicitly has an 'any' type.res .end ('ok');});// let SvelteKit handle everything else, including serving prerendered pages and static assetsapp .use (handler );app .listen (3000, () => {console .log ('listening on port 3000');});
ts
import {Cannot find module './build/handler.js' or its corresponding type declarations.2307Cannot find module './build/handler.js' or its corresponding type declarations.handler } from'./build/handler.js' ;importCannot find module 'express' or its corresponding type declarations.2307Cannot find module 'express' or its corresponding type declarations.express from'express' ;constapp =express ();// add a route that lives separately from the SvelteKit appParameter 'req' implicitly has an 'any' type.Parameter 'res' implicitly has an 'any' type.7006app .get ('/healthcheck', (, req ) => { res
7006Parameter 'req' implicitly has an 'any' type.Parameter 'res' implicitly has an 'any' type.res .end ('ok');});// let SvelteKit handle everything else, including serving prerendered pages and static assetsapp .use (handler );app .listen (3000, () => {console .log ('listening on port 3000');});
Troubleshootingpermalink
Is there a hook for cleaning up before the server exits?permalink
There's nothing built-in to SvelteKit for this, because such a cleanup hook depends highly on the execution environment you're on. For Node, you can use its built-in process.on(..)
to implement a callback that runs before the server exits:
ts
functionshutdownGracefully () {// anything you need to clean up manually goes in hereCannot find name 'db'.2304Cannot find name 'db'.. db shutdown ();}process .on ('SIGINT',shutdownGracefully );process .on ('SIGTERM',shutdownGracefully );