SvelteKit is a meta-framework, which means how you deploy it depends entirely on which adapter you choose. Pick the wrong one and you'll fight your hosting platform forever. This guide explains the adapter model and walks through a production Node deployment.
Adapters: the one decision that matters
SvelteKit builds against an adapter that targets a specific environment:
| Adapter | Output | Use when |
|---|---|---|
adapter-static | Pre-rendered HTML/CSS/JS | Fully static site, no server-side logic |
adapter-node | A Node.js server | You need SSR, form actions, API routes |
adapter-auto | Detects common hosts | Convenient but opaque; pin a real adapter for control |
If your app has +page.server.ts files, form actions, or +server.ts API endpoints that run per-request, you need a server — use adapter-node. If everything can be pre-rendered, adapter-static gives you a free, blazing-fast static deploy.
Option A: Static deployment
For a content site or marketing pages, prerender everything:
// svelte.config.js
import adapter from '@sveltejs/adapter-static';
export default {
kit: {
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: '200.html', // for SPA-style routing
}),
},
};Add export const prerender = true; in your root layout. Then npm run build produces a build/ directory of plain files. Host it anywhere that serves static assets — including PandaStack static sites, which build in microVMs and serve over the global edge for free.
Option B: Node server deployment
For SSR apps, use adapter-node:
// svelte.config.js
import adapter from '@sveltejs/adapter-node';
export default {
kit: { adapter: adapter() },
};This produces build/index.js — a standalone Node server. Containerize it:
FROM node:20-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
RUN npm prune --production
FROM node:20-slim
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/build ./build
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/package.json ./
EXPOSE 3000
CMD ["node", "build"]The adapter-node server reads PORT and HOST from the environment. Set HOST=0.0.0.0 so it accepts external connections inside the container, and bind PORT to whatever your platform assigns.
Environment variables: public vs private
SvelteKit splits env vars by visibility:
$env/static/privateand$env/dynamic/private— server-only secrets (API keys,DATABASE_URL).$env/static/publicand$env/dynamic/public— prefixedPUBLIC_, shipped to the browser.
import { DATABASE_URL } from '$env/static/private';
import { PUBLIC_API_BASE } from '$env/static/public';Never put a secret behind PUBLIC_ — it ends up in your client bundle. This trips up a lot of teams.
Deploying on PandaStack
PandaStack handles both adapter paths:
- Static SvelteKit (
adapter-static) — deploy as a static site. PandaStack auto-detects the framework, runsnpm run build, and serves the output globally. Unlimited static sites on Pro and above; the free tier includes 5. - SSR SvelteKit (
adapter-node) — deploy as a container app. PandaStack detects Node, builds via rootless BuildKit, and runsnode build. Add a managed database andDATABASE_URLis injected automatically.
Either way you get automatic SSL on custom domains, live build logs, and rollbacks from deploy history.
Production checklist
- Pick a real adapter, not
adapter-auto, for predictable behavior. - Set
HOST=0.0.0.0for containerized Node builds. - Audit
PUBLIC_env vars — no secrets in the client bundle. - Prerender what you can even in an SSR app (
export const prerender = trueper route) to cut server load. - Compress responses — adapter-node doesn't gzip by default; let your ingress/proxy handle it.
References
- SvelteKit adapters overview: https://svelte.dev/docs/kit/adapters
- adapter-node docs: https://svelte.dev/docs/kit/adapter-node
- adapter-static docs: https://svelte.dev/docs/kit/adapter-static
- SvelteKit environment variables: https://svelte.dev/docs/kit/$env-static-private
- Prerendering in SvelteKit: https://svelte.dev/docs/kit/page-options#prerender
---
Whether your SvelteKit app is fully static or server-rendered, PandaStack's free tier covers both — static sites and container apps with automatic SSL and a managed database on tap. Deploy at https://dashboard.pandastack.io