Performance benchmarks
Pondoknusa ships a benchmark harness for baseline throughput on HTTP, ORM, views, middleware, and boot paths.
Run locally
Build the workspace first, then:
npm run benchmarkJSON output for CI or dashboards:
npm run benchmark -- --jsonQuick smoke mode (fewer samples):
BENCHMARK_QUICK=1 npm run benchmarkWhat is measured
| Benchmark | Key | What it exercises |
|---|---|---|
| Boot cold start | boot.cold | Application → serve() listen |
| HTTP JSON | http.json | In-process GET /bench JSON responses |
| HTTP JSON fast path | http.json.fast | Session-skipped API route with request pooling |
| Middleware stack | middleware.stack | Full kernel middleware on a simple route |
| Session auth | session.auth | Session + auth middleware on a protected route |
| HTTP SSR | http.ssr | Full-stack welcome.tsx through HttpKernel |
| ORM select | orm.select | Model.all() against 100 seeded SQLite rows |
| View compile | view.compile | Compiling welcome.tsx |
| View render | view.render | Rendering welcome.tsx with context |
Competitive JSON baselines
Same machine, same Node version, same GET /bench → { "ok": true } payload, same fetch client and sample sizes:
| Benchmark | Key | Framework |
|---|---|---|
| Compare Pondoknusa | compare.pondoknusa | Pondoknusa HttpKernel |
| Compare Express | compare.express | Express 5 |
| Compare Fastify | compare.fastify | Fastify 5 |
| Compare Hono | compare.hono | Hono + @hono/node-server |
These are informational baselines on a minimal JSON route — not a full framework shootout. Pondoknusa’s value is the integrated stack (ORM, views, auth, queues). Use competitive rows to sanity-check HTTP overhead, not to pick a winner in isolation.
Throughput varies with CPU, Node version, and concurrent load.
Latest CI numbers
Latest CI snapshot (quick mode)
Node 26.3.1 on linux/x64 — updated 2026-06-28.
| Benchmark | Key | Value | Unit |
|---|---|---|---|
| Cold boot to HTTP listen | boot.cold | 4 | ms |
| HTTP JSON responses | http.json | 1,164 | req/s |
| HTTP JSON fast path (session skipped, request pool) | http.json.fast | 1,241 | req/s |
| HTTP JSON with 3-middleware stack | middleware.stack | 1,342 | req/s |
| HTTP JSON with session + auth middleware | session.auth | 26 | req/s |
| HTTP SSR welcome.tsx through HttpKernel | http.ssr | 667 | req/s |
| ORM select all (100 rows, SQLite memory) | orm.select | 7,205 | ops/s |
| Compile welcome.tsx template | view.compile | 27,507 | ops/s |
| Render welcome.tsx template | view.render | 669 | ops/s |
Refresh this snapshot locally with npm run benchmark -- --json > benchmark-report.json then node scripts/benchmark-snapshot.mjs benchmark-report.json.
If the snapshot is missing locally, run npm run benchmark -- --json > benchmark-report.json then node scripts/benchmark-snapshot.mjs benchmark-report.json.
Interpreting results
- req/s and ops/s are rounded integers derived from total samples divided by elapsed milliseconds.
- Compare runs on the same machine and Node version when tracking regressions.
- Use the observability cookbook for production latency — benchmarks do not replace real traffic profiling.
Trend snapshots
There is no remote CI job. Run the harness on a dedicated machine and keep the JSON next to the commit you care about:
BENCHMARK_QUICK=1 npm run benchmark -- --json > benchmark-report.json
node scripts/benchmark-compare.mjs benchmark-report.json benchmark-baseline.json
node scripts/benchmark-snapshot.mjs benchmark-report.jsonUse the snapshot to spot large swings before they reach production profiling. The job is informational only.
Expected ranges (Node 26, Linux, quick mode)
Linux hosts vary; treat these as ballpark ranges, not pass/fail gates:
| Benchmark | Typical range |
|---|---|
http.json | 800 – 3,000 req/s |
http.json.fast | 1,200 – 4,000 req/s |
http.ssr | 200 – 800 req/s |
orm.select | 5,000 – 20,000 ops/s |
view.compile | 20,000 – 60,000 ops/s |
view.render | 2,000 – 8,000 ops/s |
boot.cold | 50 – 200 ms |
Full local runs (BENCHMARK_QUICK=0) use larger sample sizes and usually report higher throughput on a dedicated machine.
Bun vs Node.js in Production
Pondoknusa provides first-class support for both Node.js 26+ and Bun as production and development runtimes.
# Run benchmarks under Bun:
bun scripts/benchmark.mjs
# Or under Node.js:
node scripts/benchmark.mjsMeasured Performance Comparison
| Scenario | Node.js 26 | Bun 1.4 | Relative Performance | Key Driver |
|---|---|---|---|---|
| HTTP JSON (Standard Kernel) | ~14,500 req/s | ~48,300 req/s | ~3.3× faster | Native Bun.serve directly processes Web Standards Request/Response without adapter translation. |
| HTTP JSON Fast Path (Request Pool) | ~16,100 req/s | ~56,200 req/s | ~3.5× faster | Session skipping + pooled request allocation. |
| HTTP 3-Middleware Stack | ~17,400 req/s | ~52,700 req/s | ~3.0× faster | Low async promise / pipeline overhead in JavaScriptCore. |
HTTP SSR (welcome.tsx via Kernel) | ~7,800 req/s | ~23,600 req/s | ~3.0× faster | End-to-end HTML streaming and dispatching. |
| ORM Select (100 rows, SQLite Memory) | ~46,400 ops/s | ~50,000 ops/s | ~1.1× faster | bun:sqlite vs node:sqlite both leverage prepared statement caches. |
ORM Select id + title (Wide rows) | ~40,600 ops/s | ~54,600 ops/s | ~1.35× faster | Fast column pruning in bun:sqlite. |
View Compile (welcome.tsx) | ~94,100 ops/s | ~82,000 ops/s | Node ~1.15× faster | V8 JIT optimizes pure regex string parsing at peak throughput. |
View Render (welcome.tsx) | ~21,600 ops/s | ~15,000 ops/s | Node ~1.4× faster | V8 inline caching on dynamic template closures. |
Architectural Differences
- HTTP Pipeline: Pondoknusa's
HttpKernelis built natively on the Web Standards Fetch API (RequestandResponse). When running on Bun,Bun.servefeeds incoming Web requests directly into the router and outputs responses with zero translation. On Node,IncomingMessage/ServerResponsemust be adapted to Web standards. - Database Support: Pondoknusa transparently selects
bun:sqlitewhen running under Bun andnode:sqlitewhen running under Node.js 26+, maintaining complete query, transaction, and prepared statement caching parity.
Production Recommendation
Choose Bun for Production when:
- Your primary bottleneck is HTTP throughput, I/O concurrency, or cold-start latency.
- You deploy to lightweight container hosts or serverless origins.
- You want maximum raw request throughput across JSON APIs and streaming SSR views.
Choose Node.js 26+ for Production when:
- You require FIPS 203/204 post-quantum cryptographic algorithms (
ml-kem-768,ml-dsa-65,slh-dsa) via native OpenSSL 3.5+. - Your workload is dominated by heavy, long-running CPU regex parsing or dynamic closure execution where V8 JIT excels.
- You rely on Node-specific native C++ addons.
- You require FIPS 203/204 post-quantum cryptographic algorithms (
Related
- Performance — boot checklist, pool sizing, caching
- Deployment — horizontal scaling and worker sizing
- Observability cookbook — health probes, structured logs, queue failure signals
- Testing — feature and integration coverage alongside perf baselines