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-qwik ship 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:

  1. qwik-bext (this package) — Vite plugin that hooks into Qwik City's build pipeline. Runs at build time. Produces dist/ and bext-adapter.json. 2. crates/bext-framework-qwik — Rust FrameworkAdapter implementation. Runs at server-config time. Detects the project, invokes bunx qwik build (or npx qwik build), normalises the output, and vends a runtime adapter. 3. bext-server vhost — per-request. Routes incoming requests to the Qwik runtime adapter, which in turn dispatches to the Node / Bun subprocess running dist/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'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 dist/server/entry.ssr.mjs, reusing the same subprocess plumbing bext already has for PHP / FastCGI. - No streaming responses yet. Qwik's renderToStream is a real streaming API. The preview buffers its output. Piping it 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 E7. - Shared viteAdapter helper not yet used. We write bext-adapter.json directly 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-bext shells out to qwik 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 that vite.config.ts includes both qwikCity() and qwikVite() plugins alongside bext(), and that qwik-bext is 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/node behind bext as a reverse proxy if you need production traffic right now. - Dependency mismatch with Qwik City v0peerDependencies is 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