Runtime: Bun-first toolchain, runtime-agnostic core

One tool runs install/test/dev; the core assumes no runtime at all — which is why the same app serves from Bun, Node, and workerd.

The feature

June's runtime story is three layers, each with a different promise:

layer promise
@junejs/core runtime-agnostic — Web standards only, zero node:*, zero drivers
host interface Bun and Node implementations of one seam (serve, spawn, sqlite)
production workerd — V8 isolates, neither Node nor Bun in the serving path

The toolchain is Bun-first: one tool covers install, test, and june dev — no tsx + nodemon + jest + esbuild assembly. That's the no-glue philosophy applied to the toolchain itself.

The core being runtime-agnostic is not hygiene, it's the deploy story: because nothing in the render core assumes a runtime, dev (Bun or Node) and production (workerd) run the SAME code, and parity is a property instead of a test burden.

The Node host is a tested claim

june dev detects its runtime; on Node it serves through node:http — with one bonus Bun can't offer: real RFC 8297 103 Early Hints interim responses. CI runs the full dev server under Node against real HTTP on every push (scripts/smoke-node.ts), so "works on Node" is continuously asserted, not assumed.

node --import tsx scripts/smoke-node.ts
# june dev → http://localhost:4399  (host: node)
# node-host smoke: OK (serve, routes, discovery, mcp)

Local SQLite: built-in, with one version floor on Node

The dev db uses the runtime's BUILT-IN SQLite — zero install, no native build: bun:sqlite on Bun, node:sqlite on Node. The one catch is Node's version: node:sqlite is flag-free only on Node ≥ 22.13.0 (the 22 LTS line) or ≥ 23.4.0. Node 22.5–22.12 / 23.0–23.3 keep it behind --experimental-sqlite, and older Node doesn't ship it at all. June detects this and, if the import fails, tells you exactly that — upgrade Node to 22.13+, or run with Bun (built-in bun:sqlite, no version floor). Bun is the always-works path; Node 22.13+ is the always-works Node.

The experimental track

There is also an owned Rust+V8 runtime (V8 snapshot boot ~12ms, bundled first render ~22ms, push-based HMR) — measured and public (benchmarks) but explicitly experimental. v0.1 ships on the Bun/Node host; the native runtime is the roadmap, not the present.

Why it matters

Runtime lock-in is glue you can't see until you migrate. A core that speaks only Web standards keeps every door open — including the one we're building toward.