Skip to content

Add Fastify: the performance-focused Node.js web framework (~33k⭐)#30

Merged
MDA2AV merged 2 commits intoMDA2AV:mainfrom
BennyFranciscus:add-fastify
Mar 16, 2026
Merged

Add Fastify: the performance-focused Node.js web framework (~33k⭐)#30
MDA2AV merged 2 commits intoMDA2AV:mainfrom
BennyFranciscus:add-fastify

Conversation

@BennyFranciscus
Copy link
Copy Markdown
Collaborator

Fastify

Adds Fastify to HttpArena — the performance-focused web framework for Node.js.

Why Fastify?

Fastify is the go-to Node.js framework when people care about performance. With ~33k GitHub stars, it's one of the most popular Node.js frameworks out there, sitting right alongside Express in mindshare but built from the ground up for speed.

Key things that make it interesting for benchmarks:

  • Schema-based serialization — Fastify can use JSON Schema to generate fast serializers
  • Highly optimized routing via find-my-way (radix tree router)
  • Low overhead — minimal abstraction over Node.js core HTTP
  • Plugin architecture with encapsulation (doesn't add overhead to hot paths)

What's in the box

  • Fastify 5.x on Node.js 22
  • Cluster mode (one worker per CPU core) — same scaling strategy as the bare node entry
  • All standard HttpArena endpoints: /pipeline, /baseline11, /baseline2, /json, /compression, /db, /upload
  • HTTP/2 + TLS on port 8443 for /static/{filename} and baseline-h2

The interesting comparison

HttpArena already has bare node — this lets people see exactly how much overhead (or optimization!) Fastify adds on top. It's the "framework vs raw" comparison that every Node.js dev has wondered about.

cc @mcollina @delvedor — would love to see how Fastify stacks up in HttpArena's benchmark suite! 🚀

…reading

Fastify's default body parser consumes the request stream before route
handlers run. The old code tried to read req.raw manually via collectBody/
collectRawBody, but the stream was already consumed — causing the Promise
to never resolve and the validation to hang indefinitely.

Fix:
- Register content-type parsers for text/plain, application/octet-stream,
  and a catch-all so req.body is always populated
- Use req.body directly in POST /baseline11 and /upload handlers
- Remove unused collectBody/collectRawBody helpers
- Bump bodyLimit to 50MB for upload test (default 1MB is too small)
@BennyFranciscus
Copy link
Copy Markdown
Collaborator Author

Found the validation hang! 🐛

Fastify's built-in content-type parsers consume the request stream before route handlers run. The old code was trying to read req.raw manually with collectBody()/collectRawBody() — but the stream was already drained by Fastify's parser, so the Promise never resolved and the validation stalled forever after the first GET test.

Fix:

  • Register proper content-type parsers (text/plain, application/octet-stream, catch-all) so req.body is populated automatically
  • Use req.body directly in POST /baseline11 and /upload handlers
  • Bumped bodyLimit to 50MB (Fastify defaults to 1MB, upload test sends ~20MB payloads)
  • Removed the now-unused stream helper functions

Should pass validation now 🤞

@github-actions
Copy link
Copy Markdown
Contributor

Benchmark Results

Framework: fastify | Profile: all profiles

fastify / baseline / 512c (p=1, r=0, cpu=unlimited)
  Best: 919012 req/s (CPU: 9340.0%, Mem: 11.8GiB) ===

fastify / baseline / 4096c (p=1, r=0, cpu=unlimited)
  Best: 887240 req/s (CPU: 9263.1%, Mem: 12.3GiB) ===

fastify / baseline / 16384c (p=1, r=0, cpu=unlimited)
  Best: 776276 req/s (CPU: 9433.2%, Mem: 12.5GiB) ===

fastify / pipelined / 512c (p=16, r=0, cpu=unlimited)
  Best: 2303929 req/s (CPU: 9136.2%, Mem: 5.4GiB) ===

fastify / pipelined / 4096c (p=16, r=0, cpu=unlimited)
  Best: 2335110 req/s (CPU: 9055.3%, Mem: 7.2GiB) ===

fastify / pipelined / 16384c (p=16, r=0, cpu=unlimited)
  Best: 2227764 req/s (CPU: 8309.1%, Mem: 7.7GiB) ===

fastify / limited-conn / 512c (p=1, r=10, cpu=unlimited)
  Best: 248682 req/s (CPU: 3590.5%, Mem: 9.9GiB) ===

fastify / limited-conn / 4096c (p=1, r=10, cpu=unlimited)
  Best: 248206 req/s (CPU: 3590.9%, Mem: 9.4GiB) ===

fastify / json / 4096c (p=1, r=0, cpu=unlimited)
  Best: 556760 req/s (CPU: 9683.4%, Mem: 5.8GiB) ===

fastify / json / 16384c (p=1, r=0, cpu=unlimited)
  Best: 509553 req/s (CPU: 8858.9%, Mem: 6.1GiB) ===

fastify / upload / 64c (p=1, r=0, cpu=unlimited)
  Best: 572 req/s (CPU: 7910.5%, Mem: 9.5GiB) ===

fastify / upload / 256c (p=1, r=0, cpu=unlimited)
  Best: 526 req/s (CPU: 8583.6%, Mem: 17.7GiB) ===

fastify / upload / 512c (p=1, r=0, cpu=unlimited)
  Best: 502 req/s (CPU: 8320.7%, Mem: 21.3GiB) ===

fastify / compression / 4096c (p=1, r=0, cpu=unlimited)
  Best: 12466 req/s (CPU: 11928.0%, Mem: 8.5GiB) ===

fastify / compression / 16384c (p=1, r=0, cpu=unlimited)
  Best: 12127 req/s (CPU: 11405.2%, Mem: 8.3GiB) ===

fastify / noisy / 512c (p=1, r=0, cpu=unlimited)
  Best: 776292 req/s (CPU: 9063.4%, Mem: 10.6GiB) ===

fastify / noisy / 4096c (p=1, r=0, cpu=unlimited)
  Best: 808892 req/s (CPU: 9088.9%, Mem: 11.7GiB) ===

fastify / noisy / 16384c (p=1, r=0, cpu=unlimited)
  Best: 672309 req/s (CPU: 8046.0%, Mem: 12.3GiB) ===

fastify / mixed / 4096c (p=1, r=5, cpu=unlimited)
  Best: 38458 req/s (CPU: 10763.2%, Mem: 9.6GiB) ===

fastify / mixed / 16384c (p=1, r=5, cpu=unlimited)
  Best: 30290 req/s (CPU: 8989.9%, Mem: 8.8GiB) ===

fastify / baseline-h2 / 256c (p=1, r=0, cpu=unlimited)
  Best: 1436000 req/s (CPU: 11649.0%, Mem: 15.9GiB) ===

fastify / baseline-h2 / 1024c (p=1, r=0, cpu=unlimited)
  Best: 1072260 req/s (CPU: 11547.3%, Mem: 16.1GiB) ===

fastify / static-h2 / 256c (p=1, r=0, cpu=unlimited)
  Best: 609760 req/s (CPU: 10296.4%, Mem: 13.0GiB) ===

fastify / static-h2 / 1024c (p=1, r=0, cpu=unlimited)
  Best: 515920 req/s (CPU: 10392.9%, Mem: 14.7GiB) ===
Full log
22. Stopping all clients.
Main benchmark duration is over for thread #Stopped all clients for thread #22
19. Stopping all clients.
Stopped all clients for thread #19
Main benchmark duration is over for thread #21. Stopping all clients.
Stopped all clients for thread #21Main benchmark duration is over for thread #10. Stopping all clients.

Main benchmark duration is over for thread #Stopped all clients for thread #10
1. Stopping all clients.
Main benchmark duration is over for thread #Stopped all clients for thread #1
30. Stopping all clients.
Main benchmark duration is over for thread #59Stopped all clients for thread #Main benchmark duration is over for thread #30
Main benchmark duration is over for thread #. Stopping all clients.6. Stopping all clients.

Main benchmark duration is over for thread #20. Stopping all clients.
Stopped all clients for thread #6
Main benchmark duration is over for thread #126. Stopping all clients.
18Stopped all clients for thread #. Stopping all clients.
59Stopped all clients for thread #126

Stopped all clients for thread #18
Main benchmark duration is over for thread #32. Stopping all clients.
Stopped all clients for thread #32
Stopped all clients for thread #20
Main benchmark duration is over for thread #26. Stopping all clients.
Stopped all clients for thread #26
Main benchmark duration is over for thread #47. Stopping all clients.
Stopped all clients for thread #47
Main benchmark duration is over for thread #53. Stopping all clients.
Main benchmark duration is over for thread #34. Stopping all clients.
Main benchmark duration is over for thread #16. Stopping all clients.
Stopped all clients for thread #53
Stopped all clients for thread #34
Stopped all clients for thread #16
Main benchmark duration is over for thread #122. Stopping all clients.
Stopped all clients for thread #122
Main benchmark duration is over for thread #37. Stopping all clients.
Stopped all clients for thread #37
Main benchmark duration is over for thread #27. Stopping all clients.
Stopped all clients for thread #27
Main benchmark duration is over for thread #41. Stopping all clients.
Stopped all clients for thread #41
Main benchmark duration is over for thread #14. Stopping all clients.
Main benchmark duration is over for thread #62. Stopping all clients.
Stopped all clients for thread #14
Stopped all clients for thread #62
Main benchmark duration is over for thread #85. Stopping all clients.
Stopped all clients for thread #85
Main benchmark duration is over for thread #51. Stopping all clients.
Stopped all clients for thread #51
Main benchmark duration is over for thread #87. Stopping all clients.
Stopped all clients for thread #87
Main benchmark duration is over for thread #52. Stopping all clients.
Stopped all clients for thread #52
Main benchmark duration is over for thread #90. Stopping all clients.
Stopped all clients for thread #90
Main benchmark duration is over for thread #104. Stopping all clients.
Main benchmark duration is over for thread #102. Stopping all clients.
Stopped all clients for thread #Main benchmark duration is over for thread #10440. Stopping all clients.

Stopped all clients for thread #102
Stopped all clients for thread #40
Main benchmark duration is over for thread #100. Stopping all clients.
Main benchmark duration is over for thread #Main benchmark duration is over for thread #11038. Stopping all clients.
Stopped all clients for thread #Stopped all clients for thread #110
Main benchmark duration is over for thread #107. Stopping all clients.
Stopped all clients for thread #107
Main benchmark duration is over for thread #68. Stopping all clients.
Stopped all clients for thread #68
Main benchmark duration is over for thread #7. Stopping all clients.
Main benchmark duration is over for thread #60. Stopping all clients.
Stopped all clients for thread #7
Stopped all clients for thread #60
Main benchmark duration is over for thread #100
88Main benchmark duration is over for thread #35. Stopping all clients.Main benchmark duration is over for thread #. Stopping all clients.
Main benchmark duration is over for thread #28. Stopping all clients.
Main benchmark duration is over for thread #93Stopped all clients for thread #Stopped all clients for thread #. Stopping all clients.Main benchmark duration is over for thread #2861
. Stopping all clients.
88
Main benchmark duration is over for thread #
94. Stopping all clients.Stopped all clients for thread #61
Stopped all clients for thread #93

Stopped all clients for thread #35
Stopped all clients for thread #94
Main benchmark duration is over for thread #11. Stopping all clients.
Main benchmark duration is over for thread #Main benchmark duration is over for thread #101Main benchmark duration is over for thread #. Stopping all clients.Main benchmark duration is over for thread #
76108. Stopping all clients.

Stopped all clients for thread #11
Stopped all clients for thread #101
63. Stopping all clients.
81. Stopping all clients.
Stopped all clients for thread #63
Main benchmark duration is over for thread #55. Stopping all clients.
Stopped all clients for thread #81
Stopped all clients for thread #55
Main benchmark duration is over for thread #78. Stopping all clients.
Stopped all clients for thread #78
Main benchmark duration is over for thread #96. Stopping all clients.
Stopped all clients for thread #96
Main benchmark duration is over for thread #49. Stopping all clients.
Stopped all clients for thread #49
Main benchmark duration is over for thread #8. Stopping all clients.
Stopped all clients for thread #8
Main benchmark duration is over for thread #79. Stopping all clients.
Stopped all clients for thread #79
Main benchmark duration is over for thread #56. Stopping all clients.
Stopped all clients for thread #56
Main benchmark duration is over for thread #43. Stopping all clients.
Stopped all clients for thread #43
Main benchmark duration is over for thread #66. Stopping all clients.
Stopped all clients for thread #66
Main benchmark duration is over for thread #83. Stopping all clients.
Stopped all clients for thread #83
Main benchmark duration is over for thread #103. Stopping all clients.
Stopped all clients for thread #103
. Stopping all clients.
Stopped all clients for thread #76
Main benchmark duration is over for thread #116. Stopping all clients.
Stopped all clients for thread #116
Main benchmark duration is over for thread #119. Stopping all clients.
Stopped all clients for thread #119
Main benchmark duration is over for thread #29. Stopping all clients.
Main benchmark duration is over for thread #70. Stopping all clients.
Stopped all clients for thread #29
Stopped all clients for thread #108
Stopped all clients for thread #70
. Stopping all clients.
Stopped all clients for thread #38
Main benchmark duration is over for thread #118. Stopping all clients.
Stopped all clients for thread #118
Main benchmark duration is over for thread #105. Stopping all clients.
Stopped all clients for thread #105
Main benchmark duration is over for thread #74. Stopping all clients.
Stopped all clients for thread #74
Main benchmark duration is over for thread #84. Stopping all clients.
Stopped all clients for thread #84
Main benchmark duration is over for thread #109. Stopping all clients.
Stopped all clients for thread #109
Main benchmark duration is over for thread #86. Stopping all clients.
Stopped all clients for thread #86
Main benchmark duration is over for thread #65. Stopping all clients.
Stopped all clients for thread #65
Main benchmark duration is over for thread #106. Stopping all clients.Main benchmark duration is over for thread #
Stopped all clients for thread #106
Main benchmark duration is over for thread #97. Stopping all clients.
Stopped all clients for thread #97
Main benchmark duration is over for thread #99. Stopping all clients.
Stopped all clients for thread #99
Main benchmark duration is over for thread #57. Stopping all clients.
Stopped all clients for thread #57
Main benchmark duration is over for thread #91. Stopping all clients.
Main benchmark duration is over for thread #64. Stopping all clients.
Stopped all clients for thread #91
Stopped all clients for thread #64
Main benchmark duration is over for thread #71. Stopping all clients.
Stopped all clients for thread #71
112Main benchmark duration is over for thread #. Stopping all clients.
82Stopped all clients for thread #112
. Stopping all clients.
Stopped all clients for thread #82
Main benchmark duration is over for thread #114. Stopping all clients.
Stopped all clients for thread #114
Main benchmark duration is over for thread #67. Stopping all clients.
Stopped all clients for thread #67
Main benchmark duration is over for thread #115. Stopping all clients.
Stopped all clients for thread #115
Main benchmark duration is over for thread #89. Stopping all clients.Main benchmark duration is over for thread #
69. Stopping all clients.
Stopped all clients for thread #89
Stopped all clients for thread #69
Main benchmark duration is over for thread #73. Stopping all clients.
Main benchmark duration is over for thread #54. Stopping all clients.
Stopped all clients for thread #73
Stopped all clients for thread #54
Main benchmark duration is over for thread #117. Stopping all clients.
Stopped all clients for thread #117

finished in 5.06s, 515920.00 req/s, 8.04GB/s
requests: 2579600 total, 2682000 started, 2579600 done, 2579600 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 2645900 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 40.18GB (43140717459) total, 26.44MB (27725228) headers (space savings 89.46%), 40.07GB (43026660577) data
                     min         max         mean         sd        +/- sd
time for request:     5.02ms    822.54ms    186.50ms     61.93ms    80.24%
time for connect:     4.66ms       1.48s    121.54ms    198.15ms    96.39%
time to 1st byte:    25.63ms       1.55s    204.42ms    199.31ms    96.00%
req/s           :     279.87      759.72      503.58       75.24    69.04%
  CPU: 10392.9% | Mem: 14.7GiB

=== Best: 515920 req/s (CPU: 10392.9%, Mem: 14.7GiB) ===
[dry-run] Results not saved (use --save to persist)
httparena-bench-fastify
httparena-bench-fastify
[skip] fastify does not subscribe to baseline-h3
[skip] fastify does not subscribe to static-h3
[skip] fastify does not subscribe to unary-grpc
[skip] fastify does not subscribe to unary-grpc-tls
[skip] fastify does not subscribe to echo-ws
[restore] Restoring CPU governor to powersave...

@BennyFranciscus
Copy link
Copy Markdown
Collaborator Author

Fastify benchmarks are in — Node.js showing up strong! 🔥

🚀 Pipelined: 2.34M req/s at 4096c — cluster mode with Node workers absolutely crushing it
Baseline: 919K at 512c — nearly 1M req/s from Node.js!
Limited-conn: 249K at 512c
📊 JSON: 557K at 4096c — V8's JSON.stringify is no joke
🗜️ Compression: 12.5K — solid for Node
📤 Upload: 572 req/s at 64c — working correctly
🔀 Mixed: 38K at 4096c
🔊 Noisy: 808K at 4096c
🌐 H2 baseline: 1.44M at 256c — HTTP/2 multiplexing really helps here
🌐 H2 static: 610K at 256c

These are genuinely impressive numbers for a JavaScript runtime. Fastify's low-overhead design + Node cluster mode is a great combo. The H2 numbers especially stand out.

Ready for merge! 🚀

@MDA2AV
Copy link
Copy Markdown
Owner

MDA2AV commented Mar 15, 2026

@BennyFranciscus check numbers on TechEmpower

@BennyFranciscus
Copy link
Copy Markdown
Collaborator Author

Checked TechEmpower for Fastify — it's consistently the fastest mainstream Node.js framework across rounds.

In TFB Round 22, Fastify with clustering lands around 300-500K req/s on JSON (physical hardware, 28 cores). Their plaintext (pipelined) test gets into the 1-2M range depending on the run. Express, for comparison, sits around 50-100K in the same tests — Fastify's fast-json-stringify and find-my-way router give it a massive edge.

Our HttpArena numbers track well:

  • 919K baseline vs TFB's ~400K JSON — our test hardware has more cores and our baseline test is simpler (no JSON serialization overhead in plaintext)
  • 2.34M pipelined vs TFB's ~1.5M plaintext — cluster mode scaling is consistent across both

Fastify's own benchmarks page (fastify.dev/benchmarks) shows ~47K req/s single-process, which matches the per-worker throughput we'd expect from our cluster results.

Bottom line: numbers are consistent with TFB. Fastify is doing what it does best — being the fastest thing in the Node.js ecosystem by a significant margin.

@MDA2AV MDA2AV self-requested a review March 16, 2026 15:02
@MDA2AV MDA2AV merged commit 11f5747 into MDA2AV:main Mar 16, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants