The numbers
Benchmarked
in the open.
Reproducible benchmarks comparing Pyxle against popular web frameworks — every framework implements identical endpoints in its native multi-process production mode, measured from a separate load-generator box so the harness is never the ceiling. No cherry-picking, and the tests Pyxle loses are shown too.
01 — Method
How the numbers were made.
- Generator
- oha v1.14 — on a separate box
- Hardware
- 2× AWS c7i.2xlarge (8 vCPU each)
- Protocol
- 100 connections · median of 3 reps
- Duration
- 12s per test, 8s warmup
- Workers
- 8 per framework (native multi-process)
- Correctness
- 0 errors · 0 non-2xx · 0 timeouts
Measured July 2026 on two dedicated EC2 instances in the same subnet: all seven frameworks on one box, the load generator on the other, over the private network. Off-box generation is the point — a generator sharing the server's cores becomes the bottleneck and clips the fastest frameworks toward each other, so the chart ends up measuring the harness instead of the server. Keeping the generator on its own hardware is what makes the spread between frameworks real.
Every framework runs its native multi-process production mode at 8 workers: Pyxle via pyxle serve --workers 8 with its full middleware stack, FastAPI and Django on uvicorn (uvloop), Flask on gunicorn, Express and Hono on Node's cluster module, and Next.js as 8 clustered next start processes. Endpoint parity is verified before every run — each framework must return an identical JSON shape (and equivalent SSR DOM) or the run aborts. A separate single-worker pass measures per-core throughput. Database: SQLite (WAL), 1,000 pre-seeded rows. Versions: Pyxle 0.7.1 (on Starlette 0.37.2, the release pinned by the shared benchmark environment), Hono 4.12, Express 5.2, Next.js 16.2 (React 19.2), FastAPI 0.139, Django 5.2, Flask 3.1, Node 22.23.
These numbers have not been re-measured for the 0.9 line. Re-running the suite needs the two-box setup described above, and we would rather leave a figure we actually took — saying plainly which version it came from — than publish an estimate of what a newer release would do.
Harness: Source code (run it yourself) ↗
02 — Findings
Six numbers, before the tables.
Every one is backed by a chart or table further down — including the one we lose.
- ~2.2×
- Next.js throughput at dynamic SSR, per core
- 2–3×
- smaller HTML for the same DOM — no hydration blob
- ±3%
- of FastAPI on JSON — ahead once real work appears, behind on a single-row read
- ~5×
- more throughput with one flag: pyxle serve --workers 8
- 0
- errors, timeouts, or non-2xx across the whole suite
- Hono
- owns raw JSON — a Node ultralight, and we say so
03 — Dynamic SSR
Server-side rendering: faster than Next.js.
The full page re-rendered on every request — the apples-to-apples match for Pyxle's @server loader and Next.js's force-dynamic. On equivalent pages (same data, same DOM, parity-verified), per core, Pyxle is 2.1–2.3× faster at every complexity — with roughly half the median latency everywhere.
| Page rendered per request | Pyxle req/s · p50 | Next.js req/s · p50 | Pyxle advantage |
|---|---|---|---|
| Landing pageHero, feature grid, stats — a typical marketing home | 1,151 · 84ms | 524 · 183ms | 2.20× |
| 300-row data tableA large inventory table, fully server-rendered | 158 · 644ms | 75 · 1344ms | 2.11× |
| Nested dashboardStat cards, grouped category cards, and a data table | 237 · 419ms | 103 · 983ms | 2.30× |
| API route, same appA JSON endpoint served through each full SSR app | 11,784 · 8ms | 2,149 · 45ms | 5.48× |
Bytes on the wire — same DOM, per response
Per core, at 100 concurrent connections. Both frameworks render React on the server — Pyxle via a persistent Node.js worker pool, Next.js via React Server Components, which serialize the component tree into every response as the RSC hydration data the bars above measure. The fair caveat: this measures pages that must render per request (personalized, authenticated, real-time). Genuinely static content is served from cache by both frameworks — a different workload from the live render measured here.
04 — API throughput
Endpoint performance, side by side.
Each framework implements identical API endpoints. Pyxle runs its full middleware stack (SSR support, GZip compression, server actions). API-only frameworks run leaner stacks by design.
Form Submission (POST)
Parse a JSON body, validate fields, return a response. Measures the request-processing pipeline.
JSON Serialization
Return a static JSON object. Measures pure framework and serialization overhead.
Health Check
A minimal endpoint. Measures raw framework routing overhead.
Single DB Query
Read one random row from SQLite with a persistent per-worker connection. The driver dominates here, not the framework.
Multiple Queries (5)
Read 5 random rows from SQLite. Measures query-loop performance.
Multiple Queries (20)
Read 20 random rows from SQLite. A heavier database workload where the query loop dominates.
Pyxle serves these through its full production middleware stack — ahead of FastAPI on form POST and the multi-query pages, a few percent behind on the trivial endpoints and about 10% on the single-row read. The Node ultralights own raw JSON by an order of magnitude — that's the toggle above, shown, not hidden.
05 — Scaling
One flag, every core.
The same app on the same 8-core box — the only change is the --workers flag. Pyxle runs an independent server process per core, with no load balancer and no shared state to configure.
$pyxle serve --workers 8
- JSON serialization
- 11,820 59,766 req/s · 5.1×
- Form POST
- 10,705 52,438 req/s · 4.9×
- Single DB query
- 3,816 29,299 req/s · 7.7×
- Five-query page
- 1,961 24,681 req/s · 12.6×
1 worker → 8 workers, 100 concurrent connections — about 5× on JSON and form, and more on the database endpoints (mean 9.0× across the six API tests, to FastAPI's 7.4× on the same move — Pyxle out-scales it on every one). The multi-query tests scale past 8× because a single worker serializes its blocking SQLite reads; eight workers overlap them. Per core, the optimized Node runtimes still lead — scaling is how Pyxle puts whole machines to work, not a claim to the per-core crown. Requires Pyxle 0.4.3+.
06 — Full disclosure
Where Pyxle loses.
A benchmark page that only shows wins is an ad. Same boxes, same run — these are the workloads where Pyxle is not the fastest choice today.
Raw JSON and health-check throughput
Hono 212,528 vs Pyxle 59,766 req/s, JSON
On endpoints that do almost no work, Hono — an ultralight Node framework with no SSR — is about 3.5× faster, and FastAPI edges Pyxle by a few percent on JSON and the bare health ping too. Per core, V8's HTTP pipeline and a leaner ASGI stack lead when there's nothing to render — and an off-box harness is what keeps a gap like this visible instead of letting the generator's own ceiling flatten it. Pyxle's answer is holding level with FastAPI while carrying a full render pipeline, the ~2 ms tails, and near-linear scaling — not a claim to the raw-JSON crown.
Raw database reads
Hono 172,870 · Express 47,937 · FastAPI 32,319 vs Pyxle 29,299 req/s, single row
Node's native better-sqlite3 bindings dominate single-row SQLite reads, and FastAPI's leaner stack leads Pyxle by about 10% there. Add real work and Pyxle moves back ahead of FastAPI (24,681 req/s on the five-query page to 22,013), but the single-read crown belongs to the native drivers.
07 — Real-world
pyxle.dev scores 100 on Lighthouse.
This marketing site is a live Pyxle app — server-rendered on every request. Google's Lighthouse (desktop) rates it a perfect 100 across all four categories.
pyxle.dev.Verify on PageSpeed Insights ↗08 — Reproduce
Run them yourself.
All benchmark code is open source — the endpoint implementations, the Next.js apps, the parity checks, and the SSR test pages. Two commands give you the quick run on your own hardware.
git clone https://github.com/pyxle-dev/benchmarkscd benchmarks && ./bench.sh --suite=all --workers=auto
The quick run keeps the generator on your own machine — fine for relative standings, but absolute numbers read low because the generator shares the CPU. The published numbers use the two-box flow: ./bench.sh --serve-only --workers=auto on the server box, ./bench.sh --generate-only --target=<server-ip> --suite=all on the client box. The README documents it step by step.