DX: a loop with no assembly
Bun-first toolchain, runtime-agnostic core
One tool — Bun — runs install, test, and dev; the no-glue philosophy applied
to the toolchain. Meanwhile @junejs/core assumes no runtime at all, which
is what lets the same app serve from Bun, Node, and workerd (see
Runtime).
Zero-config dev
june dev runs with nothing installed around it: declared resources get
local defaults — db is an embedded SQLite file, blob a local directory,
kv in-memory. No Docker, no service to start. The same sqlite() declaration
becomes a Cloudflare binding (D1, R2, KV) on deploy, so the SAME code runs on
Workers.
Parity by construction
Dev and the built worker share one render core — projections, discovery,
document, layout wrapping are the same code. june build freezes what dev
discovers at request time (routes, config, content, prerender) and the golden
parity tests assert byte-level agreement. "Works in dev, breaks deployed" is
treated as a framework bug, not your bug.
An oracle for every artifact
june info # routes + the agent surface (tools, discovery endpoints)
june gen # freeze content — and see exactly what the manifest holds
june deploy --dry-run # the full build + config resolution, no upload — CI runs this
Conventions a coding agent can't misread are conventions a human can't misread either: file-system routing, plain SQL migrations, one config file that exists to turn things off.
Reload on save — server and browser
june dev watches your app and restarts the server on change — content
edits regenerate the frozen manifest first, so the next request is fresh.
A restart is the honest reload on a JS host (a module cache can't be
selectively invalidated without lying about state); --no-watch opts out.
The browser follows by itself: every dev page holds an SSE connection to the dev server, and the restart is the signal — the connection drops, the page reconnects, and reloads on success. Dev-only by construction (injected by the dev server wrapper, never the render pipeline), so it cannot leak into a build or skew dev/built parity.
Push-based HMR belongs to the experimental Rust+V8 runtime track: on save,
the server re-renders and pushes the RSC diff over the live channel —
measured median 73ms from save to flight pushed, isolate rebuild at
16ms (benchmarks, scripts/bench-hmr.ts). The push loop
is the same machinery as production live-RSC — dev speed and the live
features are one investment.
Why it matters
DX debt compounds: every adapter you hand-wire is something to misconfigure, and now there are two kinds of authors (humans and agents) misconfiguring it. The framework's job is to make the default loop need no assembly at all.