Performance (measured)
Real numbers, not a hunch — measured on this deployment. bext's interactivity floor (the JS a client pays to make an island interactive) is in the single-digit kilobytes, and zero before interaction in lazy mode.
Interactivity JS, compressed (gzip)
What a client downloads to make a counter interactive. The resume runtime (~3KB) is cached once across every island and page; each extra island adds only ~0.6KB — or nothing until interaction.
Head-to-head: the same app in five frameworks (measured)
We built the same app — a server-rendered 24-product grid + counter, theme toggle and search filter, all verified in a real browser — in all five frameworks, then forced each to render fresh on every request (no cache, no prerender; proven by a timestamp that changes on every request). Production builds and servers on activ-2; RPS/TTFB via oha -c 50.
| Framework | Client JS (gz) | TTFB | RPS (uncached) | p99 | Build |
|---|---|---|---|---|---|
| bext (PRISM) | 5.6 KB | 6.0 ms | 4,742 | 71 ms | ~4 KB* |
| Astro | 0.33 KB | 12.3 ms | 3,807 | 20 ms | 432 KB |
| Remix | 101 KB | 12.2 ms | 1,011 | 75 ms | 335 KB |
| Qwik | 35 KB | 42.6 ms | 938 | 73 ms | 249 KB |
| Next.js | 145 KB | 21.1 ms | 575 | 141 ms | 5.2 MB |
Time to First Byte
Rust render + ISR cache. The full resumability page leaves in ~18ms (first-byte and total are the same over the local network), across three warm requests.
Methodology (reproducible)
# interactivity floor — gzipped bytes a client actually pays
curl -s https://demo.bext.dev/islands/ResumableCounter.js | gzip -c | wc -c # 589
curl -s https://demo.bext.dev/islands/__resume-runtime.js | gzip -c | wc -c # 2970 (cached once)
# TTFB (Rust + ISR cache) — three warm samples
for i in 1 2 3; do curl -s -o /dev/null \
-w '%{time_starttransfer}s\n' https://demo.bext.dev/examples/resumability; done
# → 0.018s 0.020s 0.019s
# full harness (TTFB + JS bytes + request count per page)
node harnesses/browser/bench.mjs