Skip to content

Deploy SvelteKit

deploybase supports SvelteKit with adapter-static, in two shapes: a fully prerendered static site, or a single-page app that routes in the browser. Server-side rendering and form actions that require a Node.js runtime are not supported.

  • SvelteKit 2+
  • @sveltejs/adapter-static installed
Terminal window
npm install -D @sveltejs/adapter-static
What you are building Use
Marketing site, docs, blog, portfolio Prerendered static site
App with client-side routing or dynamic routes you cannot list at build time Single-page app

Both paths use adapter-static and both deploy the same way. Only svelte.config.js and your root layout differ.

Every route is written to its own HTML file at build time, so each URL is served as real HTML. This is the better choice for content sites: search engines and social previews get a full page without running JavaScript.

svelte.config.js:

import adapter from '@sveltejs/adapter-static';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: undefined,
precompress: false,
strict: true,
}),
},
};
export default config;

src/routes/+layout.js:

export const prerender = true;

Every route has to be prerenderable. For dynamic routes that SvelteKit cannot find by crawling links, export an entries function from the corresponding +page.js.

SPA mode emits one app shell, 200.html, and lets the SvelteKit router resolve URLs in the browser. Use it when routes depend on data that only exists at runtime, such as a dashboard behind a login.

svelte.config.js:

import adapter from '@sveltejs/adapter-static';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: '200.html',
precompress: false,
strict: false,
}),
},
};
export default config;

src/routes/+layout.js:

export const ssr = false;

You do not need export const prerender = true in SPA mode, and you do not need to enumerate dynamic routes.

The fallback: '200.html' above is the only thing you need: deploybase picks that file up on its own and serves it for any path with no matching file, so deep links and hard reloads land in your app. See SPA fallback and custom 404 pages for the full detection rules and the _redirects alternative.

Mixing prerendering and SPA mode is fine: routes you mark prerender = true are still written as their own HTML files, and the fallback only covers what is left over.

Setting Value
Framework sveltekit
Build command npm run build
Output directory build
Docker image node:24-alpine
Terminal window
curl -X POST https://api.deploybase.eu/api/v1/projects \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My SvelteKit Site",
"framework": "sveltekit",
"git_repo_url": "https://github.com/user/sveltekit-site.git",
"git_provider": "github"
}'

Build fails with “adapter-static requires prerender”: adapter-static needs to know what to write to disk, and one of your routes cannot be prerendered. There are two ways forward.

  1. Prerender everything. Add export const prerender = true; to src/routes/+layout.js and export entries for any dynamic route SvelteKit cannot reach by crawling. Best for content sites.
  2. Switch to SPA mode. Set fallback: '200.html' in the adapter options and export const ssr = false; in your root +layout.js. Routes resolve in the browser, and deploybase serves 200.html for paths with no matching file.

Setting strict: false on its own also silences the build error, but any route left unrendered has no file behind it. Without a 200.html (or a _redirects catch-all) in the build output, those URLs fall through to your 404 page.

Deep links 404 in a SPA: check that build/200.html exists in the build output. If your adapter config sets fallback to something else, such as index.html, rename it to 200.html or add a _redirects file with /* /index.html 200.

Using bun instead of npm: bun is supported natively. If your repository has a bun.lock or bun.lockb committed, deploybase detects it and installs with bun automatically. To set it explicitly:

Terminal window
curl -X PATCH https://api.deploybase.eu/api/v1/projects/PROJECT_ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"package_manager": "bun"}'

The build command stays npm run build, which runs the build script from your package.json against the dependencies bun installed. See Build System for the full package-manager reference.