Deploy with adapter-node in Docker
adapter-node produces a standalone Node server: npm run build emits a build/ directory you run with node build. This is the self-host path, and the one that fits the lab’s Docker-first convention.
Install the adapter
npx sv add sveltekit-adapter="adapter:node"
or manually (note: in SvelteKit 3 the adapter config lives in the Vite plugin, not svelte.config.js):
// vite.config.js
import adapter from '@sveltejs/adapter-node';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
sveltekit({
adapter: adapter(),
}),
],
});
Build and run
npm run build
HOST=127.0.0.1 PORT=4000 node build
The server binds 0.0.0.0:3000 by default; PORT, HOST, and SOCKET_PATH override that. The build bundles dev dependencies via Rolldown - only dependencies stay external, so put runtime-only packages there.
Dockerfile
Multi-stage, distroless-style, matching the lab’s container conventions:
# Build.
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Deploy.
FROM node:22-alpine AS release
WORKDIR /
COPY --from=build /app/build /build
COPY --from=build /app/node_modules /node_modules
COPY --from=build /app/package.json /package.json
ENV NODE_ENV=production
EXPOSE 3000
USER node
CMD ["node", "build"]
Run it capped per lab convention (small web service: 1 CPU / 1G) and put lab-caddy in front for tailnet review lanes.
Behind a reverse proxy
SvelteKit derives the request origin from the host header. Behind lab-caddy (or any proxy), forward the original protocol and host:
PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host node build
Gotcha: only set these behind a trusted proxy - clients can spoof
x-forwarded-*on direct connections. For a fixed canonical origin (needed for CSRF checks on form posts and remote-function calls), setpaths.originin the Vite plugin config instead.
Other adapters
The same pattern applies to adapter-cloudflare (Workers), adapter-static (fully prerendered sites), adapter-vercel, and adapter-netlify; all are wired through the same Vite plugin option in kit 3.