Bun v1.4.1 shipped today with a number that made me do a double take. In their idle-memory benchmark, a Next.js SSR app running on Bun 1.3.14 sat at 1,303 MB of resident memory. The same app on Bun 1.4.1 sits at 142 MB. Node.js 26 sits at 195 MB. A patch release, fixing 202 issues, cut idle memory by roughly 11x on their heaviest test case.
That number is dramatic enough that it deserves scrutiny rather than a retweet. So I spent this evening going through every published benchmark I could find: the official Bun 1.4 and 1.4.1 posts, an independent three-runtime benchmark from late August, and Node.js 26's own release notes. Full disclosure up front: I am primarily a JVM backend engineer by day, six years of Spring Boot, but I run a growing pile of Node-based services for my own AI agent infrastructure, and every one of them is a candidate for this decision. What follows is the decision framework I built for myself, with the actual numbers.
What changed in Bun 1.4.1, in plain terms
Bun 1.4.0 landed on August 20 and was a milestone release: the port from Zig to Rust finished, they added 1,517 tests from Node.js's own test suite, and they claim over 2,900 bug fixes. Today's 1.4.1 is the cleanup pass, and its headline changes are all about memory and correctness:
- JIT code gets deleted after idle periods. JavaScriptCore now throws away JIT-generated machine code after an extended idle stretch. This is the single change behind the 1,303 MB to 142 MB Next.js drop. A long-running server that goes quiet between traffic bursts no longer hoards compiled code it is not using.
- The numbers across the board are now boring, in a good way. After 60 seconds of load and 3 minutes idle on Linux x64: Express 53 MB on Bun vs 83 MB on Node.js 26. Fastify 55 vs 89. Hono 34 vs 92. Elysia 44 vs 96. Bun is consistently 30 to 60 percent lighter at idle, not just on the cherry-picked case.
- Bun.write() streams to disk now. Writing a 128 MiB download used to add 161 MB to peak memory. It now adds 13 MB. Fetch and S3 downloads pause when you stop reading the body instead of buffering everything.
- HTTP/2 landed in Bun.serve. Same port as HTTP/1.1, negotiated over ALPN on TLS. Their benchmark shows 291,512 requests per second on a hello-world GET versus 55,619 for Node's http2 on the same hardware, which I would file firmly under synthetic-benchmark caution, more on that below.
- A real security fix you should know about. Bun's fetch() previously verified TLS certificates against a custom Host header instead of the URL's hostname when tls.servername was unset. Their own post calls the old behavior "an insecure default" and recommends upgrading if your proxy passes user-supplied Host headers to fetch(). Node's fetch and curl already did the right thing here.
That last point matters for how you should read everything else in this article. Bun 1.4.1 is a maturity release. Some of what it fixes were the exact reasons to stay on Node six months ago.
The throughput picture, with the synthetic caveat
The Bun posts show big wins: 6.8x faster than Node.js 26 on hello-world HTTP/2 GETs, 4.5x on 4 KB POSTs, shrinking to 1.3x on 64 KB responses and 2.1x on streaming workloads. Read that gradient carefully, because it tells you where the advantage actually lives. The simpler and smaller the response, the more of the request lifecycle is runtime overhead that Bun engineered away. The more real work your handler does, the more the gap closes.
Independent data agrees with the shape but not the magnitude. RepoFlow's August 24, 2026 benchmark ran Node.js 24, 25, and 26 against Bun and Deno across 14 tests on an Apple M4, 15 runs each, reporting medians. The result: Bun led 8 of 14 tests, Deno led 5, and Node led 1, with Bun strongest on server-style throughput, HTTP and large JSON parsing, and Node winning the SHA-256 hashing test at 1,024-byte inputs. Nobody got swept. When a vendor shows 6.8x and an independent lab shows "led 8 of 14, lost the crypto test," the truth is workload-dependent, exactly as The Primeagen has argued about synthetic benchmark marketing for years: production performance is dominated by your I/O and your database, not the runtime's hello-world ceiling.
Where Bun's advantage is not synthetic at all is cold start and idle cost:
- Startup: 5.1 ms for hello.js on Linux versus 27.2 ms for Node.js 26. On Windows, 15.5 ms versus 40.1 ms. Roughly 2 to 5x faster depending on platform.
- Idle CPU: Bun 1.4 claims a 5x reduction in idle CPU for a hello-world server, and published a screenshot of Claude Code's production CPU profile dropping from p99 24% to 10% after upgrading to Bun 1.4.
- The reason is architectural. Bun runs on JavaScriptCore, the Safari engine, optimized for fast startup, on a Zig and now Rust base with modern I/O. Node runs V8, the Chrome engine, optimized for long-running hot paths, on a C++ and libuv base. V8 bets on your process living for hours; JavaScriptCore bets on getting out of the way when it does not need to run.
The compatibility question, honestly answered
Speed is pointless if your dependencies break. This was always the real Bun blocker, and it is the area that moved most in 2026.
Bun 1.4 added 1,517 passing tests from the Node.js test suite, their largest compatibility jump since 1.0. Per-module, they now report: node:events, node:trace_events, and node:sqlite pass 100% of Node's own tests, node:quic passes 99%, and node:http, node:fs, node:cluster, node:timers, node:zlib, node:vm, and node:stream all pass 97%. That is not 100% compatible, and the Bun post says so plainly, but the frontier frameworks have noticed: Playwright 1.4, vitest, Nuxt dev, OpenTelemetry's http and fs instrumentation, and Datadog's dd-trace all now run on Bun. TypeORM starts. amqplib connects to RabbitMQ. testcontainers works.
Node.js 26, released May 5, counters on a different axis: Temporal enabled by default, V8 14.6, Undici 8, and the removal of long-deprecated legacy stream internals. It is a stability-and-modernization release, not a performance one, and the community read it the same way; the Reddit thread on release day described it as "a big bunch of small fixes and minor deprecations." Node 26 enters LTS in October 2026, which is exactly when conservative teams will standardize on it.
One more compatibility data point that I find underrated: the Bun blog's own Claude Code example. Anthropic runs one of the largest long-running agent applications in production on Bun, and their measured p99 CPU dropped by more than half after the 1.4 upgrade. When the company that owns your runtime's parent company runs its flagship product on it, that is a production validation no benchmark chart provides.
My decision checklist
Here is the framework I landed on for my own services, in the order I would apply it:
- Greenfield API or CLI tool? Use Bun. Fast startup, one binary instead of a runtime plus TypeScript toolchain, built-in test runner and bundler, 30 to 60 percent lower idle memory. The blast radius of a compatibility surprise is small and the ecosystem flags (jest-compatible tests, ws, Express) mostly just work now.
- Existing Express or Fastify service with a small surface? Try it this quarter. Run your test suite under Bun first, then a canary instance behind your load balancer. The 1.4.x line fixed enough Node-compat gaps that this is no longer reckless; just budget an evening for edge cases, because "97% of node:fs tests passing" still means 3%.
- Large monolith, native modules, or deep Node.js internals? Stay on Node 26. The remaining 3% lives disproportionately in the places monoliths live: worker edge cases, inspector tooling, native addons. Node 26 hits LTS in October and carries you to 2029. The migration savings rarely justify the audit cost.
- Latency-critical crypto or hashing hot paths? Node won the one independent test it led. SHA-256 at 1,024-byte inputs went to Node 26. Profile before assuming Bun is faster at your workload.
- Whatever you pick, upgrade Bun to 1.4.1 immediately if you run it. The Host-header TLS verification fix alone justifies the bump, and the idle memory reclamation is the difference between a 142 MB and a 1.3 GB container limit.
The honest summary: in 2023 this was a hype comparison, in 2025 it was an early-adopter gamble, and in September 2026 it has finally become a boring infrastructure decision you can make from a checklist. Boring is the best thing a runtime war can become.
What are you running in production right now, Bun, Node, or Deno? If you moved off Node, what broke? I am genuinely collecting war stories for a follow-up, so tell me in the comments.
I write about backend engineering, AI infrastructure, and the tooling decisions in between, several times a week. Subscribe, it is free, and you will get the follow-up benchmark with real workloads when I run my own services through it.
Top comments (0)