Skip to main content
The @sveltejs/adapter-node adapter generates a standalone Node server for your SvelteKit application.

Installation

npm install -D @sveltejs/adapter-node

Usage

Add the adapter to your svelte.config.js:
/// file: svelte.config.js
import adapter from '@sveltejs/adapter-node';

/** @type {import('@sveltejs/kit').Config} */
const config = {
  kit: {
    adapter: adapter({
      // Adapter options
      out: 'build',
      precompress: true,
      envPrefix: ''
    })
  }
};

export default config;

Configuration options

These options are defined in the adapter source code:
/// file: packages/adapter-node/index.d.ts
interface AdapterOptions {
  out?: string;        // Output directory (default: 'build')
  precompress?: boolean;  // Enable gzip/brotli compression (default: true)
  envPrefix?: string;     // Environment variable prefix (default: '')
}

out

The directory where the server build output will be written.
adapter({
  out: 'my-server-build'
})

precompress

Enables precompression of assets using gzip and brotli. This is enabled by default.
adapter({
  precompress: true  // Creates .gz and .br files alongside assets
})
From the adapter implementation:
/// file: packages/adapter-node/index.js
if (precompress) {
  builder.log.minor('Compressing assets');
  await Promise.all([
    builder.compress(`${out}/client`),
    builder.compress(`${out}/prerendered`)
  ]);
}

envPrefix

A prefix for environment variables. For example, if you set envPrefix: 'MY_APP_', then environment variables like MY_APP_HOST and MY_APP_PORT will be used.
adapter({
  envPrefix: 'MY_APP_'
})

Deployment

After building your app, the output directory contains everything needed to run your application:
1

Build the app

npm run build
2

Run the server

node build/index.js

Environment variables

The adapter recognizes several environment variables to configure the server at runtime:
VariableDescriptionDefault
PORTPort to listen on3000
HOSTHost to listen on0.0.0.0
ORIGINOrigin URL for the appAuto-detected
XFF_DEPTHDepth of X-Forwarded-For header to trust1
ADDRESS_HEADERHeader to read client address from-
PROTOCOL_HEADERHeader to read protocol from-
HOST_HEADERHeader to read host from-
PORT_HEADERHeader to read port from-
BODY_SIZE_LIMITMaximum request body size512K
PORT=4000 node build/index.js
Here’s how environment variables are used in the handler:
/// file: packages/adapter-node/src/handler.js
const origin = parse_origin(env('ORIGIN', undefined));
const xff_depth = parseInt(env('XFF_DEPTH', '1'));
const address_header = env('ADDRESS_HEADER', '').toLowerCase();
const protocol_header = env('PROTOCOL_HEADER', '').toLowerCase();
const host_header = env('HOST_HEADER', '').toLowerCase();
const port_header = env('PORT_HEADER', '').toLowerCase();
const body_size_limit = parse_as_bytes(env('BODY_SIZE_LIMIT', '512K'));

Build output structure

The adapter generates the following directory structure:
build/
├── index.js          # Server entry point
├── handler.js        # Request handler
├── env.js           # Environment configuration
├── server/          # Server-side code
│   ├── index.js     # SvelteKit server
│   └── manifest.js  # App manifest
├── client/          # Client assets
│   └── _app/        # Built client code
└── prerendered/     # Prerendered pages

Platform object

The adapter provides access to the raw Node.js request object via event.platform:
/// file: src/hooks.server.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
  // Access the raw Node request
  const { req } = event.platform;
  
  console.log('Request headers:', req.headers);
  
  return resolve(event);
}
The platform.req object is the raw Node.js IncomingMessage object from the http module.

Advanced usage

You can use the generated handler.js as middleware in your own Node server:
import express from 'express';
import { handler } from './build/handler.js';

const app = express();

// Add custom middleware
app.use('/api/custom', (req, res) => {
  res.json({ custom: 'endpoint' });
});

// Use SvelteKit handler for everything else
app.use(handler);

app.listen(3000);
The adapter bundles dependencies using Rollup, but dependencies listed in package.json are kept as external imports. Make sure to install production dependencies before deploying.