SvelteKit Integration

SvelteKit is Svelte's full-stack framework with file-system routing, form actions, and first-class SSR. @sveltejs/adapter-bext is the SvelteKit adapter that targets bext: you keep SvelteKit's authoring experience, and bext provides the HTTP layer, cache, WAF, HTTP/2/3, and plugin ecosystem that every adapter otherwise reinvents.

Preview release. The adapter and the Rust-side framework runtime in crates/bext-framework-sveltekit ship as part of bext's E6 milestone. See the ecosystem roadmap for what's landed and what's still on the follow-up list.

Install

bun add -d @sveltejs/adapter-bext

Peer dependencies: @sveltejs/kit ^2.

Configure

In svelte.config.js:



export default {
  kit: {
    adapter: adapter({
      out: "build",
      runtime: "bun",
    }),
  },
};

The adapter implements SvelteKit's Adapter contract (adapt(builder)) and writes the build output plus a bext-adapter.json manifest into the configured output directory.

Options

Option Type Default Description
out string "build" Directory to emit the build artefacts into.
runtime "node" | "bun" "bun" Preferred runtime for the SSR worker. Informational; bext decides.

Build

bun run build

The build emits:

build/
  client/             hashed JS, CSS, fonts
  server/             SSR entry + manifest
  prerendered/        statically prerendered pages
  manifest.js         generated SvelteKit manifest module
  bext-adapter.json   metadata for the bext runtime

bext-adapter.json is the contract between @sveltejs/adapter-bext and crates/bext-framework-sveltekit. It looks like:

{
  "adapter": "@sveltejs/adapter-bext",
  "version": "0.1.0-preview",
  "runtime": "bun",
  "serverEntry": "server/index.js",
  "clientDir": "client",
  "prerenderedDir": "prerendered",
  "manifest": "manifest.js",
  "generatedAt": "2026-04-11T12:00:00.000Z"
}

Serve

Via bext.config.toml

[framework]
type = "sveltekit"
build_dir = "build"

[build]
script = "build/server/index.js"
watch_dirs = ["src"]
live_reload = true

Then:

bext serve

bext's vhost detects the project as SvelteKit (on svelte.config.*

+ @sveltejs/kit in package.json), reads the build output, and dispatches requests to the SvelteKit handler through the framework runtime adapter.

Via bext new

bext new my-svelte-app --template @bext/starter-sveltekit
cd my-svelte-app
bun install
bun run build
bext serve

The starter ships with svelte.config.js, a +layout.svelte, two pages (/ and /about), and the bext.config.toml plumbing pre-wired.

How it fits together

Three moving parts collaborate on every SvelteKit request through bext:

  1. @sveltejs/adapter-bext (this package) — SvelteKit Adapter implementation. Runs at build time. Produces build/ and bext-adapter.json. 2. crates/bext-framework-sveltekit — Rust FrameworkAdapter implementation. Runs at server-config time. Detects the project, invokes bunx vite build (or npx vite build), normalises the output, and vends a runtime adapter. 3. bext-server vhost — per-request. Routes incoming requests to the SvelteKit runtime adapter, which in turn dispatches to the Node / Bun subprocess running build/server/index.js.

How it compares to adapter-node

@sveltejs/adapter-node produces a standalone Node server you run yourself. @sveltejs/adapter-bext skips the HTTP layer — bext provides that — and just emits the compiled SSR entry, the prerendered pages, and the static client assets. bext then adds TLS, HTTP/2/3, cache, WAF, compression, and the full plugin ecosystem without SvelteKit needing to know about any of them.

If you currently run adapter-node behind nginx, adapter-bext replaces both layers in one move.

What works today

- File-system routing (src/routes/**)

- Dynamic routes ([param], [...rest])

- Layouts and nested layouts (+layout.svelte)

- Load functions (+page.server.ts, +page.ts)

- Form actions (+page.server.ts actions export)

- API routes (+server.ts)

- Prerendered pages (export const prerender = true)

- Static assets served from build/client/

- TypeScript + Svelte 4 and 5

Current limitations

  • Subprocess dispatch is still TODO. For the E6 preview, the runtime adapter is a descriptor only — bext-framework-sveltekit's handle_request returns a not-yet-wired error. The follow-up is to teach bext-server's vhost to dispatch to the Node / Bun subprocess that imports build/server/index.js, reusing the same subprocess plumbing bext already has for PHP / FastCGI. - No streaming responses yet. SvelteKit's handle can return a streaming Response. The preview buffers those. Piping them through bext's response writer lands with the streaming FrameworkAdapter::render hook. - No edge runtime support. This adapter targets Node / Bun. Cloudflare-Workers-style edge output is out of scope for E6. - Native Rust build deferred. @sveltejs/adapter-bext shells out to vite build — SvelteKit's build is a Vite plugin set and rewriting it in Rust is out of scope for E6. A direct turbopack / bun pipeline is on the ecosystem roadmap.

Troubleshooting

  • vite build produced no build/ directory — the build ran but didn't emit the expected layout. Double-check that svelte.config.js imports @sveltejs/adapter-bext and passes it as kit.adapter, and that the package is installed as a dev-dependency. - SvelteKitRuntime::handle_request is not wired yet — you're seeing the E6 descriptor-only limitation. Build works, detection works, but per-request dispatch is scheduled for the follow-up. Until then, use adapter-node behind bext as a reverse proxy if you need production traffic right now. - Dependency mismatch with SvelteKit v1peerDependencies is set to "@sveltejs/kit": "^2". If your lockfile pins v1, the adapter contract won't resolve — upgrade SvelteKit or use an older adapter.

Related docs

- @bext/starter-sveltekit — starter scaffold