Benchmarks#

Janux measured against react 19.2, preact 10.29, solid 2.0-beta, svelte 5.56 and vue-vapor 3.6-rc across 19 multi-framework suites — client runtime, hydration, SSR, streaming and shipped bytes. The harness is a direct port of octane's benchmark infrastructure (MIT, Dominic Gannaway — see the credits below), whose correctness gates are the point: a framework that posts numbers must first prove the DOM it produced is right, keyed rows kept their identity, focus and caret survived, and every mount got its cleanup.

Everything here is reproducible from benchmarks/ in the repo: bun run bench runs the suites, node benchmarks/report.mjs renders the full position report. Timing numbers below are from a full run on 2026-08-02 (with the 2026-08-05 compiler-pass deltas where noted) — Apple M4 Pro, 24 GB, macOS 26.5, Node 26, Bun 1.3, Chromium 151 headless. Shipped-bytes numbers are deterministic and current as of 2026-08-06, after boot features became imports. Absolute milliseconds are a property of that machine; the ratios are the claim, and CI re-checks a committed set of ratio guards weekly — a 2026-08-06 verification run kept all 23 green.

Where Janux wins#

Resume instead of hydration. A Janux page becomes interactive by reading its serialized state snapshots and installing delegated listeners — no component re-execution, no event replay. That design shows up everywhere the hydration suites measure it:

janux react preact solid svelte vue-vapor
News page: make interactive 0.39ms 2.86ms 1.91ms 2.12ms 1.66ms 1.90ms
Hydration, 6× CPU throttle 10.70ms 57.62ms 18.76ms 26.80ms 27.44ms 24.76ms
Hydration work on the main thread (6×) 5.26ms 19.88ms 13.16ms 20.86ms 17.12ms 18.14ms
Controlled page, 6× throttle 12.12ms 58.22ms 18.16ms 27.32ms 29.28ms 25.22ms

Fine-grained updates. <For> gives every row its own reactive scope and class={() => …} binds a single attribute, so a change costs what it changed rather than one whole-island render (keys and lists, <For>):

krausest op (1,000 rows) janux react preact solid svelte vue-vapor
swap rows 1.10ms 3.98ms 0.44ms 0.24ms 0.36ms 0.22ms
create 10,000 rows 68.94ms 136.86ms 57.98ms 15.60ms 26.74ms 18.20ms
clear 10,000 rows 38.40ms 41.74ms 36.54ms 25.58ms 30.36ms 24.38ms
reverse 1.95ms 2.24ms 2.08ms 1.10ms 16.04ms 1.43ms
rotate last to front 0.51ms 1.51ms 0.17ms 0.09ms 0.13ms 0.67ms

Shipped bytes vs the React baseline. The always-on Janux client runtime — signals, reconciler, delegated events, resume, the agent bridge and the WebMCP surface — is 29.0KB gzip; the same krausest app ships 30.9KB total against react's 62.1KB. The optional layers (agent glow, the simulated cursor, i18n, the query cache) are boot features you import, so an app that doesn't use one ships none of it. Pages with no islands ship no JavaScript at all, which no suite here can even express.

js_gzip, krausest app preact solid svelte vue-vapor janux react
total 10.0KB 14.1KB 18.4KB 24.1KB 30.9KB 62.1KB

Whole-app parity and wins. Resetting a 512-field form: 14.74ms against react's 38.64 (preact 40.84, solid 36.02). One update pass across 512 bound fields (scaling-curves update_512): 16.84ms vs react's 45.58. A burst of 128 delegated events: 10.72ms vs react's 18.12. Mount/update/unmount lifecycle cycles land at react's number with exact cleanup accounting (49.35ms vs 49.56), and a 512-subscriber selector store runs zero selector calls across 20 unrelated parent re-renders.

Where Janux does not win (yet)#

Honest numbers, with the cause understood. Across the 19 suites, 88 of 156 janux/react cells are ahead of react and 68 are behind; the full signed table is in benchmarks/BASELINE-2026-07.md.

  • Building rows in bulk. Creating 1,000 rows costs 6.56ms against react's 4.88 and solid's 1.90. A Janux row carries an Owner, a signal and an effect so it can update in isolation; solid's rows are compiled templates with none of that bookkeeping. The reorder ops sit at ~0.5ms against react's 0.15 for the same reason — the floor is the keyed diff plus the per-row scope, not the DOM move.
  • Island boot. Making a throttled page interactive after an interaction takes 10.34ms against react's 4.06 — Janux wins the end-to-end hydration rows by 5× but pays more for the first island it wakes.
  • Selecting one row among 1,000 costs 0.82ms where react-with-memo pays 0.30 and solid 0.04. The binding rewrites exactly one attribute per row now; what remains is a thousand effect invocations.
  • Typing into 512 controlled fields (controlled-form typing) is behind: 83.2ms against react's 49.1. Leaf-path subscriptions took it from 87.5 and removed the sibling-binding blowup, but the per-keystroke path still does more work than react's memoized inputs.
  • SSR throughput. Rendering the 50-card news page takes 0.26ms against react's 0.07. Streaming end-to-end is at parity (50.86ms vs 51.06 on the staggered schedule, out-of-order boundary swaps included) because data latency dominates, but the shell's time-to-first-byte is 1.40ms against react's 0.06: Janux waits one turn per suspense boundary to see whether its content settles, and inlines it when it does.
  • App bytes for TodoMVC: 1.3KB gzip against react's 1.1KB. Every Janux intent carries a schema and a description, because the MCP tools agents call are generated from them.
  • One extra DOM element per island. The <janux-island> host is the resumability boundary, so the node census reads 10,073 against react's 10,072.

What the benchmarks already paid for#

Porting the harness found and fixed real framework issues before any tuning started: intent bodies now batch to one reactive flush (a krausest update was 1816ms before, 7.2ms after), keyed morph landed because the reorder suite's node-identity gate demanded it, and the SSR chunk coalescer was rewritten after the throughput suite's sustained-render loop exposed unbounded retention (~800KB pinned per render, OOM; now flat). The full optimization log, including the attempts that didn't survive, lives in benchmarks/BASELINE-2026-07.md.

Credits#

The harness, suites and rival fixtures derive from octane's benchmarks (MIT, Copyright (c) 2026 Dominic Gannaway) — runner, statistics, correctness-gate methodology and the ratio-guard CI model are theirs. The js-framework fixtures derive upstream from krausest/js-framework-benchmark (Apache-2.0). Full notices in benchmarks/LICENSE-OCTANE and CREDITS.md.