SvelteKit Static Export Guide: adapter-static to Vercel Deploy
Complete SvelteKit static export — adapter-static config, prerender routes, trailing slashes, and Vercel deployment that works.
Tested on: SvelteKit 2.16, adapter-static 3.0, Node 22 Goal: Ship a blog with zero server runtime. Time lost: 6 hours on one typo.
TL;DR
- Install @sveltejs/adapter-static; set fallback only if needed.
- Export prerender = true in root +layout.ts.
- Match trailingSlash with Vercel; output to build/.
Starting point
npm create svelte@latest my-blog
cd my-blog
npm install -D @sveltejs/adapter-static
svelte.config.js (working version)
import adapter from '@sveltejs/adapter-static';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: '404.html',
precompress: false,
strict: true
})
}
};
export default config;
Enable prerender globally
src/routes/+layout.ts:
export const prerender = true;
Without this, npm run build dies on the first dynamic route.
Error #1 — the one that ate my afternoon
@/sveltejs/adapter-static: all routes must be fully prerenderable,
but found the following routes that are dynamic:
- src/routes/blog/[slug]
Fix: add +page.ts inside [slug]/:
import type { PageLoad } from './$types';
import { error } from '@sveltejs/kit';
export const prerender = true;
export const load: PageLoad = async ({ params }) => {
const posts = import.meta.glob('/src/content/*.md', { eager: true });
const match = Object.entries(posts).find(([path]) =>
path.includes(params.slug)
);
if (!match) throw error(404, 'Not found');
return { post: (match[1] as { metadata: Record<string, string> }).metadata };
};
And enumerate slugs for the adapter:
export function entries() {
return [
{ slug: 'hello-world' },
{ slug: 'static-export-notes' }
];
}
Error #2 — trailing slash mismatch on Vercel
404 on /about/ but /about works
svelte.config.js kit section:
kit: {
trailingSlash: 'always',
adapter: adapter({ /* ... */ })
}
Match Vercel project setting: Trailing Slash → Always.
Build & verify locally
npm run build
npx serve build
# curl -I http://localhost:3000/about/
Vercel deploy
Framework preset: Other. Output directory: build. No install command changes needed.
Result
Build time: 42s
Output size: 1.2 MB (gzipped assets ~280 KB)
Lighthouse Performance: 97
Zero serverless invocations on free tier
Static export is not "easier than SSR" — it's stricter. Every route must declare how it prerenders. Once that's done, hosting is trivial.
FAQ
How do I export SvelteKit as a static site?
Use @sveltejs/adapter-static, set prerender = true in +layout.ts, and configure kit.adapter in svelte.config.js.
Can SvelteKit static sites deploy to Vercel?
Yes — set outputDirectory to build and framework: null. Align trailingSlash with Vercel URL behavior.
What is adapter-static fallback option?
fallback: '200.html' enables SPA mode for dynamic routes. Omit fallback for fully prerendered static sites.