Not every SvelteKit app needs a server. If your content is known at build time — a blog, docs, a marketing site, a portfolio — you can prerender the whole thing to static HTML and serve it from a CDN. That's faster, cheaper, and infinitely scalable. This guide covers deploying a SvelteKit app as a static site with adapter-static.
When static is the right choice
Use adapter-static when:
- All pages can be prerendered at build time.
- You don't need per-request server logic (form actions, server-side auth, dynamic API routes that must run on the server).
- You want CDN distribution and zero server cost.
If you need server endpoints or per-request SSR, use a Node adapter instead. For everything else, static wins.
Installing the static adapter
npm install -D @sveltejs/adapter-staticConfigure it in svelte.config.js:
import adapter from '@sveltejs/adapter-static';
export default {
kit: {
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: undefined, // set to '200.html' for SPA fallback
precompress: true,
}),
},
};Enabling prerendering
Tell SvelteKit to prerender. The simplest approach is a root layout that opts everything in:
// src/routes/+layout.js
export const prerender = true;With prerender = true at the root, SvelteKit crawls your app from the entry point, follows links, and generates static HTML for every reachable page. Any route that can't be prerendered (e.g. it reads request headers) will throw at build time, which is a useful guardrail.
Dynamic routes
For dynamic routes like /blog/[slug], give SvelteKit the list of slugs to prerender via entries:
// src/routes/blog/[slug]/+page.js
export const prerender = true;
export function entries() {
return [
{ slug: 'first-post' },
{ slug: 'second-post' },
];
}Or return the slugs from your content source (a CMS, a folder of markdown) so the list stays in sync automatically.
SPA fallback
If parts of your app are client-rendered and use dynamic routes that can't be enumerated, set a fallback so the CDN serves a single HTML shell for unmatched paths:
adapter({ fallback: '200.html' })This turns your build into a hybrid: prerendered pages where possible, client-side routing for the rest. Note this disables the build-time guarantee that every route resolves — use it deliberately.
Building
npm run buildThe output lands in build/ — plain HTML, CSS, JS, and assets. No server, no node_modules needed at runtime. With precompress: true, you also get .gz and .br variants so the CDN can serve pre-compressed responses.
Deploying to a static host
Static SvelteKit deploys are trivial because there's nothing to run — just files to serve. On PandaStack you deploy it as a static site: the platform auto-detects SvelteKit, runs npm run build, and serves the build/ output from a global CDN. Static builds run in fast microVMs, and your site gets a custom domain with automatic SSL.
The key settings the platform infers (and you can override):
| Setting | Value |
|---|---|
| Install command | npm ci (overridable: yarn/pnpm/bun) |
| Build command | npm run build |
| Output directory | build |
Caching and immutable assets
SvelteKit fingerprints its JS/CSS filenames with content hashes, so those assets are safely cacheable forever. HTML should be revalidated on each request so new deploys appear immediately. A good CDN config caches hashed assets with immutable, max-age=31536000 and serves HTML with a short or revalidating cache. Most static hosts (PandaStack included) apply sensible defaults automatically.
Environment variables at build time
Static sites can only use env vars available at build time, and only PUBLIC_-prefixed vars are exposed to the client bundle:
import { PUBLIC_API_BASE } from '$env/static/public';There's no server to read secrets at runtime, so never put secrets in a static build — anything in the bundle is public.
Deploying
Push your repo and connect it as a static site. The platform installs, builds, and publishes to the CDN. Live build logs show prerender progress and surface any route that failed to prerender.
git push origin mainConclusion
SvelteKit's adapter-static plus prerender = true turns your app into pure static files: enumerate dynamic routes with entries(), optionally add an SPA fallback, and deploy the build/ output to a CDN. It's the cheapest, fastest, most scalable way to ship content sites.
Try it on PandaStack's free tier, which includes static sites with custom domains and automatic SSL — connect your SvelteKit repo at [dashboard.pandastack.io](https://dashboard.pandastack.io) and it builds and publishes to the CDN with one push.
References
- [SvelteKit: adapter-static](https://svelte.dev/docs/kit/adapter-static)
- [SvelteKit: Prerendering](https://svelte.dev/docs/kit/page-options#prerender)
- [SvelteKit: Single-page apps (SPA fallback)](https://svelte.dev/docs/kit/single-page-apps)
- [SvelteKit: Environment Variables](https://svelte.dev/docs/kit/$env-static-public)
- [MDN: HTTP Caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching)