Qwik Integration
Qwik is a resumable framework that ships
essentially zero JavaScript on first paint — components hydrate
lazily, on interaction. qwik-bext is the Qwik City adapter that
targets bext: you keep Qwik'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-qwikship as part of bext's E7 milestone. See the ecosystem roadmap for what's landed and what's still on the follow-up list.
Install
bun add -d qwik-bext
Peer dependencies: @builder.io/qwik-city ^1.
Configure
In vite.config.ts:
export default defineConfig({
plugins: [
qwikCity(),
qwikVite(),
bext({
outDir: "dist",
runtime: "bun",
}),
],
});
qwik-bext returns a Vite plugin that runs at closeBundle,
writing a bext-adapter.json manifest beside Qwik's own build
output so crates/bext-framework-qwik can pick it up.
Options
| Option | Type | Default | Description |
|---|---|---|---|
outDir |
string |
"dist" |
Output directory relative to the project root. |
ssr |
string |
"server/entry.ssr.mjs" |
SSR entry relative to outDir. |
runtime |
"node" | "bun" |
"bun" |
Preferred runtime for the SSR worker. Informational. |
staticGenerate |
boolean |
false |
Run Qwik City's static-generation pass during build. |
Build
bun run build
The build emits:
dist/
build/ hashed client assets (JS, CSS, fonts)
static/ optional prerendered HTML
server/
entry.ssr.mjs SSR entry — exports default { render }
q-manifest.json Qwik manifest with symbol → chunk map
bext-adapter.json metadata for the bext runtime
bext-adapter.json is the contract between qwik-bext and
crates/bext-framework-qwik. It looks like:
{
"adapter": "qwik-bext",
"version": "0.1.0-preview",
"runtime": "bun",
"serverEntry": "server/entry.ssr.mjs",
"clientDir": "build",
"staticDir": "static",
"manifest": "q-manifest.json",
"generatedAt": "2026-04-11T12:00:00.000Z"
}
Serve
Via bext.config.toml
[framework]
type = "qwik"
build_dir = "dist"
[build]
script = "dist/server/entry.ssr.mjs"
watch_dirs = ["src"]
live_reload = true
Then:
bext serve
bext's vhost detects the project as Qwik (on qwik.config.* or
vite.config.* + @builder.io/qwik-city in package.json), reads
the build output, and dispatches requests to the Qwik handler
through the framework runtime adapter.
Via bext new
bext new my-qwik-app --template @bext/starter-qwik
cd my-qwik-app
bun install
bun run build
bext serve
The starter ships with vite.config.ts, a shared layout.tsx, two
pages (/ and /about), and the bext.config.toml plumbing
pre-wired.
How it fits together
Three moving parts collaborate on every Qwik request through bext:
qwik-bext(this package) — Vite plugin that hooks into Qwik City's build pipeline. Runs at build time. Producesdist/andbext-adapter.json. 2.crates/bext-framework-qwik— RustFrameworkAdapterimplementation. Runs at server-config time. Detects the project, invokesbunx qwik build(ornpx qwik build), normalises the output, and vends a runtime adapter. 3.bext-servervhost — per-request. Routes incoming requests to the Qwik runtime adapter, which in turn dispatches to the Node / Bun subprocess runningdist/server/entry.ssr.mjs.
How it compares to @builder.io/qwik-city/adapters/node
Qwik City's node adapter produces a standalone Node server you
run yourself. qwik-bext skips the HTTP layer — bext provides that —
and just emits the compiled SSR entry plus hashed client assets.
bext then adds TLS, HTTP/2/3, cache, WAF, compression, and the full
plugin ecosystem without Qwik needing to know about any of them.
If you currently run adapter-node behind nginx, qwik-bext
replaces both layers in one move — and Qwik's resumability keeps the
wire bytes low even before bext's cache kicks in.
What works today
- File-system routing (src/routes/**)
- Nested layouts (layout.tsx)
- Route loaders (routeLoader$)
- Form actions (routeAction$)
- Dynamic routes ([param], [...rest])
- Static generation pass (optional, via staticGenerate: true)
- Static assets served from dist/build/
- TypeScript + Qwik 1.x
Current limitations
- Subprocess dispatch is still TODO. For the E7 preview, the
runtime adapter is a descriptor only —
bext-framework-qwik'shandle_requestreturns a not-yet-wired error. The follow-up is to teach bext-server's vhost to dispatch to the Node / Bun subprocess that importsdist/server/entry.ssr.mjs, reusing the same subprocess plumbing bext already has for PHP / FastCGI. - No streaming responses yet. Qwik'srenderToStreamis a real streaming API. The preview buffers its output. Piping it through bext's response writer lands with the streamingFrameworkAdapter::renderhook. - No edge runtime support. This adapter targets Node / Bun. Cloudflare-Workers-style edge output is out of scope for E7. - SharedviteAdapterhelper not yet used. We writebext-adapter.jsondirectly from a plugin rather than going through@builder.io/qwik-city/adapters/shared/vite. Once we're comfortable with the direct peer-dep, we'll migrate. - No native Rust build.qwik-bextshells out toqwik build— Qwik's build is a Vite plugin set and rewriting it in Rust is out of scope for E7. A direct turbopack / bun pipeline is on the ecosystem roadmap.
Troubleshooting
qwik build produced no dist/ directory— the build ran but didn't emit the expected layout. Double-check thatvite.config.tsincludes bothqwikCity()andqwikVite()plugins alongsidebext(), and thatqwik-bextis installed as a dev-dependency. -QwikRuntime::handle_request is not wired yet— you're seeing the E7 descriptor-only limitation. Build works, detection works, but per-request dispatch is scheduled for the follow-up. Until then, use@builder.io/qwik-city/adapters/nodebehind bext as a reverse proxy if you need production traffic right now. - Dependency mismatch with Qwik City v0 —peerDependenciesis set to"@builder.io/qwik-city": "^1". If your lockfile pins v0, the adapter contract won't resolve — upgrade Qwik City or use an older adapter.
Related docs
- @bext/starter-qwik — starter scaffold
- bext framework overview — how adapters
compose with bext's request pipeline
- SvelteKit on bext — another
FrameworkAdapterimplementation with the same three-part shape