Home / Articles

Node vs Bun vs Deno: multi-route bakeoffs beat single RPS charts

A multi-route Node.js vs Bun vs Deno bakeoff: raw throughput is real, but ops familiarity, permissions, memory and DB-bound routes decide the architecture.

Publisher: REACTAPP.TOP7 min read1713 words

This article is published in English.

Sources: I Rebuilt the Same API on Node.js, Bun, and Deno. The Surprising Difference Wasn’t Throughput

The benchmark that matters has more than one route

Bare HTTP RPS charts made one race look finished: Bun far ahead, Deno next, Node behind. Architecture decisions need more than a single synthetic route.

export async function handle(request: Request): Promise<Response> {
  const url = new URL(request.url);

  if (url.pathname === "/health") {
    return Response.json({ status: "ok" });
  }

  if (url.pathname.startsWith("/v1/accounts/")) {
    const account = await accounts.find(url.pathname.split("/").pop()!);

    if (!account) {
      return Response.json({ error: "not_found" }, { status: 404 });
    }

    return Response.json(account);
  }

  return Response.json({ error: "not_found" }, { status: 404 });
}
// Bun
Bun.serve({ fetch: handle, port: 3000 });

// Deno
Deno.serve({ port: 3000 }, handle);
deno serve \
  --allow-net=0.0.0.0:3000,postgres.internal,redis.internal \
  --allow-env=DATABASE_URL,REDIS_URL,OTEL_EXPORTER_OTLP_ENDPOINT \
  --allow-read=./config \
  main.ts

Raw throughput was real, but it stopped deciding the architecture

Throughput matters at the edge of cost curves. Most business APIs become limited by databases, auth, and downstream IO long before runtime RPS caps.

Node was the least interesting runtime, which was a compliment

Node’s ecosystem gravity, ops familiarity, and predictable deployment story still win default platforms. Boring is a feature when on-call is finite.

Bun was fastest when it was allowed to be Bun

Bun shines with its own APIs and tooling. Forcing Node-compatibility paths erodes the advantage; evaluate Bun-native assumptions honestly.

Deno made permissions and telemetry part of application design

Deno’s permission model and standard library push security and observability into the runtime story—not only middleware afterthoughts.

Memory was where winners blurred

Allocate, GC, and RSS under realistic payloads mattered more than peak RPS. Memory losers become cost losers in containers.

Operational simplicity depends on what you already own

If the org already runs Node on Kubernetes with mature dashboards, switching runtimes tax-trains everyone. If greenfield and edge-heavy, Bun/Deno deserve bakeoffs with multi-route benchmarks: JSON APIs, multipart, WebSocket, and DB-bound handlers.

Closing

Rebuild the same API across runtimes to learn tradeoffs—not to crown a forever winner from one HTTP flood test. Pick the runtime that fits ops, permissions, and the bottleneck you actually have.

Publish the benchmark harness with the article’s conclusions. Irreproducible RPS screenshots should not drive platform strategy.

Include cold-start and CLI DX in the scorecard for functions/edge, not only steady-state RPS.

Track compatibility footguns: native addons, node: imports, and testing libraries that assume Node globals.

For each runtime, document the production process model (cluster, supervisor, isolations) you would actually ship.

Cost the bakeoff in engineer-days; a 4× RPS win that costs a rewrite of auth and CI is not free performance.

Keep a compatibility canary that runs the top twenty routes on each runtime nightly if you truly multi-home.

Publish the benchmark harness with the article’s conclusions. Irreproducible RPS screenshots should not drive platform strategy.

Include cold-start and CLI DX in the scorecard for functions/edge, not only steady-state RPS.

Track compatibility footguns: native addons, node: imports, and testing libraries that assume Node globals.

For each runtime, document the production process model (cluster, supervisor, isolations) you would actually ship.

Cost the bakeoff in engineer-days; a 4× RPS win that costs a rewrite of auth and CI is not free performance.

Keep a compatibility canary that runs the top twenty routes on each runtime nightly if you truly multi-home.

Publish the benchmark harness with the article’s conclusions. Irreproducible RPS screenshots should not drive platform strategy.

Include cold-start and CLI DX in the scorecard for functions/edge, not only steady-state RPS.

Track compatibility footguns: native addons, node: imports, and testing libraries that assume Node globals.

For each runtime, document the production process model (cluster, supervisor, isolations) you would actually ship.

Cost the bakeoff in engineer-days; a 4× RPS win that costs a rewrite of auth and CI is not free performance.

Keep a compatibility canary that runs the top twenty routes on each runtime nightly if you truly multi-home.

Publish the benchmark harness with the article’s conclusions. Irreproducible RPS screenshots should not drive platform strategy.

Include cold-start and CLI DX in the scorecard for functions/edge, not only steady-state RPS.

Track compatibility footguns: native addons, node: imports, and testing libraries that assume Node globals.

For each runtime, document the production process model (cluster, supervisor, isolations) you would actually ship.

Cost the bakeoff in engineer-days; a 4× RPS win that costs a rewrite of auth and CI is not free performance.

Keep a compatibility canary that runs the top twenty routes on each runtime nightly if you truly multi-home.

Publish the benchmark harness with the article’s conclusions. Irreproducible RPS screenshots should not drive platform strategy.

Include cold-start and CLI DX in the scorecard for functions/edge, not only steady-state RPS.

Track compatibility footguns: native addons, node: imports, and testing libraries that assume Node globals.

For each runtime, document the production process model (cluster, supervisor, isolations) you would actually ship.

Cost the bakeoff in engineer-days; a 4× RPS win that costs a rewrite of auth and CI is not free performance.

Keep a compatibility canary that runs the top twenty routes on each runtime nightly if you truly multi-home.

Publish the benchmark harness with the article’s conclusions. Irreproducible RPS screenshots should not drive platform strategy.

Include cold-start and CLI DX in the scorecard for functions/edge, not only steady-state RPS.

Track compatibility footguns: native addons, node: imports, and testing libraries that assume Node globals.

For each runtime, document the production process model (cluster, supervisor, isolations) you would actually ship.

Cost the bakeoff in engineer-days; a 4× RPS win that costs a rewrite of auth and CI is not free performance.

Keep a compatibility canary that runs the top twenty routes on each runtime nightly if you truly multi-home.

Publish the benchmark harness with the article’s conclusions. Irreproducible RPS screenshots should not drive platform strategy.

Include cold-start and CLI DX in the scorecard for functions/edge, not only steady-state RPS.

Track compatibility footguns: native addons, node: imports, and testing libraries that assume Node globals.

For each runtime, document the production process model (cluster, supervisor, isolations) you would actually ship.

Cost the bakeoff in engineer-days; a 4× RPS win that costs a rewrite of auth and CI is not free performance.

Keep a compatibility canary that runs the top twenty routes on each runtime nightly if you truly multi-home.

Publish the benchmark harness with the article’s conclusions. Irreproducible RPS screenshots should not drive platform strategy.

Include cold-start and CLI DX in the scorecard for functions/edge, not only steady-state RPS.

Track compatibility footguns: native addons, node: imports, and testing libraries that assume Node globals.

For each runtime, document the production process model (cluster, supervisor, isolations) you would actually ship.

Cost the bakeoff in engineer-days; a 4× RPS win that costs a rewrite of auth and CI is not free performance.

Keep a compatibility canary that runs the top twenty routes on each runtime nightly if you truly multi-home.

Publish the benchmark harness with the article’s conclusions. Irreproducible RPS screenshots should not drive platform strategy.

Include cold-start and CLI DX in the scorecard for functions/edge, not only steady-state RPS.

Multi-route benchmarks should include authenticated JSON POSTs, file upload boundaries, and a chatty ORM path—the places runtimes diverge after hello-world GETs.

Team skill graphs matter: a Bun win that stranding half the staff on unfamiliar test tooling is a deferred outage.

Watch TLS and HTTP/2 stacks; microbenchmarks on plain HTTP miss termination costs at the mesh.

Container image size and CVE scan noise differ by runtime base images—ops will weigh that beside RPS.

Contract tests against OpenAPI keep the bakeoff honest when handlers drift between ports.

Record p99 latency under contention, not only median RPS; schedulers hide different tail behaviors.

If you adopt Deno permissions, translate each grant into an architecture decision record so future services do not silently widen the sandbox.

Bun’s npm compatibility layer deserves an explicit allow/deny list of packages you will not run in production.

Node remains the compatibility baseline: measure others as deltas from Node on your real routes.

Revisit the decision quarterly; runtime scoreboards move, but so do your bottlenecks.

Multi-route benchmarks should include authenticated JSON POSTs, file upload boundaries, and a chatty ORM path—the places runtimes diverge after hello-world GETs.

Team skill graphs matter: a Bun win that stranding half the staff on unfamiliar test tooling is a deferred outage.

Watch TLS and HTTP/2 stacks; microbenchmarks on plain HTTP miss termination costs at the mesh.

Container image size and CVE scan noise differ by runtime base images—ops will weigh that beside RPS.

Contract tests against OpenAPI keep the bakeoff honest when handlers drift between ports.

Record p99 latency under contention, not only median RPS; schedulers hide different tail behaviors.

If you adopt Deno permissions, translate each grant into an architecture decision record so future services do not silently widen the sandbox.

Bun’s npm compatibility layer deserves an explicit allow/deny list of packages you will not run in production.

Node remains the compatibility baseline: measure others as deltas from Node on your real routes.

Revisit the decision quarterly; runtime scoreboards move, but so do your bottlenecks.

Multi-route benchmarks should include authenticated JSON POSTs, file upload boundaries, and a chatty ORM path—the places runtimes diverge after hello-world GETs.

Team skill graphs matter: a Bun win that stranding half the staff on unfamiliar test tooling is a deferred outage.

Watch TLS and HTTP/2 stacks; microbenchmarks on plain HTTP miss termination costs at the mesh.

Container image size and CVE scan noise differ by runtime base images—ops will weigh that beside RPS.

Contract tests against OpenAPI keep the bakeoff honest when handlers drift between ports.

Record p99 latency under contention, not only median RPS; schedulers hide different tail behaviors.

If you adopt Deno permissions, translate each grant into an architecture decision record so future services do not silently widen the sandbox.

Bun’s npm compatibility layer deserves an explicit allow/deny list of packages you will not run in production.

Node remains the compatibility baseline: measure others as deltas from Node on your real routes.