SvelteKit apps deploy to many platforms via adapters. For your own server, @sveltejs/adapter-node produces a standalone Node.js server that you run with systemd or PM2 behind Nginx.

1. Switch to adapter-node

npm i -D @sveltejs/adapter-node
// svelte.config.js
import adapter from '@sveltejs/adapter-node';

export default {
  kit: {
    adapter: adapter({ out: 'build' }),
  },
};

(If your site is fully prerenderable, adapter-static produces plain files for Nginx instead — see deploying a static site.)

2. Build

npm ci
npm run build

The output in build/ contains index.js (the server entry) and the client assets. At runtime it still needs your production dependencies:

build/
package.json
package-lock.json

Copy those to the server and install production dependencies there (npm ci --omit=dev), or bundle dependencies into the build so node_modules isn’t needed.

3. Environment variables that matter

adapter-node reads these at runtime:

Variable Purpose
HOST, PORT Bind address (use 127.0.0.1 behind Nginx)
ORIGIN Public URL, e.g. https://example.com — required for form actions’ CSRF check behind a proxy
PROTOCOL_HEADER, HOST_HEADER Alternative to ORIGIN: derive the URL from x-forwarded-proto / x-forwarded-host
ADDRESS_HEADER e.g. X-Forwarded-For — so event.getClientAddress() returns the visitor IP
XFF_DEPTH Number of trusted proxies when using X-Forwarded-For
BODY_SIZE_LIMIT Max request body (default 512 KB) — raise for uploads

Without ORIGIN (or the header settings), form submissions fail with “Cross-site POST form submissions are forbidden” behind a proxy.

App-specific variables are read through $env/dynamic/private (runtime) or $env/static/private (inlined at build time).

4. Run with systemd

# /etc/systemd/system/sveltekit.service
[Unit]
Description=SvelteKit app
After=network.target

[Service]
User=deploy
WorkingDirectory=/srv/sveltekit
Environment=NODE_ENV=production
Environment=HOST=127.0.0.1
Environment=PORT=3000
Environment=ORIGIN=https://example.com
Environment=ADDRESS_HEADER=X-Forwarded-For
Environment=XFF_DEPTH=1
Environment=BODY_SIZE_LIMIT=10M
EnvironmentFile=-/etc/sveltekit.env
ExecStart=/usr/bin/node build
Restart=always

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now sveltekit
curl -I http://127.0.0.1:3000

For zero-downtime reloads, PM2 in cluster mode works too (pm2 start build/index.js -i 2) — see the PM2 guide.

5. Nginx

server {
    listen 80;
    server_name example.com;
    client_max_body_size 10M;

    location /_app/immutable/ {
        proxy_pass http://127.0.0.1:3000;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Files under /_app/immutable/ have content hashes in their names, so a long cache is safe. (adapter-node already sends good cache headers; the explicit block helps if a CDN sits in front.) Keep client_max_body_size in line with BODY_SIZE_LIMIT.

sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d example.com

6. Deploy updates

npm ci && npm run build
rsync -az --delete build package.json package-lock.json deploy@server:/srv/sveltekit/
ssh deploy@server 'cd /srv/sveltekit && npm ci --omit=dev && sudo systemctl restart sveltekit'

Or build a Docker image in CI and pull it on the server — see Dockerize a Node.js app.

Troubleshooting

  • “Cross-site POST form submissions are forbidden” — set ORIGIN (or PROTOCOL_HEADER/HOST_HEADER).
  • Client IP is 127.0.0.1 — set ADDRESS_HEADER and XFF_DEPTH.
  • 413 on uploads — raise both BODY_SIZE_LIMIT and Nginx’s client_max_body_size.
  • Module not found at startup — production dependencies weren’t installed next to build/.

Related: deploying Next.js and Nuxt on a VPS.

  • SvelteKit
  • Svelte
  • Deployment