SvelteKit 3
The same package supports SvelteKit 3 (currently a prerelease). The adapter
detects which SvelteKit is building the app and runs the matching
implementation, so there is nothing to switch. On SvelteKit 3, static assets and
prerendered pages are embedded in the executable, and the options follow the
official @sveltejs/adapter-bun.
Options from the other SvelteKit version fail the build with an error naming them, see Migrating from the SvelteKit 2 options.
#Install
bun add -d @orochibraru/svelte-smol @sveltejs/kit@next#Usage
// vite.config.js
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import adapter from "@orochibraru/svelte-smol";
export default defineConfig({
plugins: [sveltekit({ adapter: adapter() })],
});The build runs under the Bun runtime:
bun run --bun vite build#Output
build/
├── server # the executable, assets embedded
└── healthcheck # tiny probe for Docker HEALTHCHECK./build/serverStatic assets and prerendered pages are served with an ETag, Last-Modified
and Accept-Ranges: bytes, the same way whether they are embedded or on disk.
A single byte Range gets a 206 (so <video> can seek without downloading
the whole file), a range past the end a 416, and If-Range is honoured.
Multiple ranges and malformed headers are ignored and answered with the full
body. Ranges always apply to the uncompressed file, never to a .br / .gz
variant.
#buildOptions.compile: false
A native (.node) addon like sharp can't be embedded in a binary. Set
buildOptions: { compile: false } to emit a plain bundle instead:
build/
├── index.js # the server entry, run with `bun`
├── server/ # split chunks
├── healthcheck # still a compiled binary
├── client/
└── prerendered/bun ./build/index.jsPure-JS dependencies are still bundled. Native addons resolve from
node_modules at runtime, so ship a production install alongside.
#Options
adapter({
out: "build", // output directory
precompress: false, // .br/.gz variants (compile: false only)
envPrefix: "", // prefix for the runtime env vars below
serverOptions: {}, // JSON-serializable Bun.serve() defaults; env vars win
buildOptions: {
compile: true, // true | "bun-linux-x64-musl" | { target, outfile, … } | false
// also: sourcemap, minify, bytecode, banner, footer, drop, features,
// optimizeImports, splitting
},
healthcheck: true, // or { path: "/healthz" }, or false
});compile accepts any Bun compile target string ("bun-linux-x64",
"bun-linux-arm64-musl", "bun-darwin-arm64", "bun-windows-x64", …) to
cross-compile; the healthcheck binary uses the same target.
#Runtime environment variables
| Variable | Default | Purpose |
|---|---|---|
HOST | 0.0.0.0 | Listen address |
PORT | 3000 | Listen port |
SOCKET_PATH | none | Listen on a Unix socket instead of HOST/PORT |
ORIGIN | none | Public origin, e.g. https://my.site; overrides paths.origin |
REUSE_PORT | false | SO_REUSEPORT |
IPV6_ONLY | false | Disable dual-stack |
CONNECTION_IDLE_TIMEOUT | 10 | Bun socket idle timeout in seconds, max 255 (SSE responses opt out) |
BODY_SIZE_LIMIT | 512K | Max request body (K/M/G suffixes, or Infinity) |
SHUTDOWN_TIMEOUT | 30 | Seconds to drain in-flight requests on SIGINT/SIGTERM |
DEVELOPMENT | false | Bun.serve development mode |
PROTOCOL_HEADER | none | Header carrying the forwarded protocol (e.g. x-forwarded-proto) |
HOST_HEADER | none | Header carrying the forwarded host |
PORT_HEADER | none | Header carrying the forwarded port |
ADDRESS_HEADER | none | Header carrying the client address (e.g. x-forwarded-for) |
XFF_DEPTH | 1 | Trusted-proxy depth when ADDRESS_HEADER=x-forwarded-for |
HEALTHCHECK_PATH | /_health | Endpoint the healthcheck binary probes |
HEALTHCHECK_TIMEOUT | 2000 | healthcheck binary request timeout in ms |
Set envPrefix to namespace these (envPrefix: "MY_APP_" → MY_APP_PORT).
The public origin comes from ORIGIN, read at runtime so one build can be
deployed at several origins, then SvelteKit's paths.origin config, then the
request headers above.
#Health check
With healthcheck enabled (the default) the server answers GET /_health with
{ "status": "ok", "uptime": … }, and the build also produces
build/healthcheck, which probes it over loopback (or the Unix socket) and
exits 0 when healthy, 1 otherwise:
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD ["./build/healthcheck"]It reads the same HOST / PORT / SOCKET_PATH as the server.
#Migrating from the SvelteKit 2 options
| SvelteKit 2 | SvelteKit 3 |
|---|---|
compile: false | buildOptions: { compile: false } |
target: "bun-linux-x64" | buildOptions: { compile: "bun-linux-x64" } |
name: "app" | buildOptions: { compile: { outfile: "app" } } |
bytecode, minify, sourcemap | buildOptions.* |
serveOptions | serverOptions (JSON-serializable only) |
serveAssets: false | removed, assets are embedded |
IDLE_TIMEOUT | CONNECTION_IDLE_TIMEOUT |
ASSETS_DIR | removed, assets are embedded |
This guide lives in the project repo: edit it there, and this page follows within a day.