DevTeardown
English

English comparison articles · 비교글 영어 원문 · 比较文章为英文 · 比較記事は英語 · Artículos en inglés · Articles en anglais

Runtimes & Tooling Bun vs Node.js Source review recorded 2026-11-10 · 4 min read

Bun vs Node.js

Bun's own test count says node:http passes 403 of 415 tests, and Node's own calendar says v20 died on 24 March 2026. Neither runtime charges a cent, so the bill arrives somewhere else.

Verdict

Pick Node if your service needs an API Bun documents as missing — getPeerCertificate(), SNICallback, createHook with real async ids — or if a native addon in your tree has no build for NODE_MODULE_VERSION 147. Pick Bun if the addons and APIs you depend on survive its 403-of-415 node:http count, because the runtime itself will never appear on an invoice.

In this teardown
  1. Both runtimes cost nothing, so the invoice arrives as labour
  2. Node bills you on a date you did not choose
  3. Who should not pick Node for unbuilt TypeScript
  4. Bun's own node:http count leaves 415 − 403 = 12 tests failing
  5. Who should not pick Bun: teams requiring missing APIs
  6. Bun stays MIT after Anthropic's acquisition; check before migrating
  7. Cost arithmetic
  8. Decision matrix
  9. Migration path
  10. FAQ

At a glance

Dimension Bun All-in-one Node.js Standards runtime
Product foundationJavaScriptCore runtime, rewritten in Rust for 1.4Node core plus the npm ecosystem
Pricing modelFree · MIT · no paid tierFree · MIT · support past Maintenance LTS via OpenJS partners
Hosting and deploymentYes — a single executableYes — your own machines
Runtime and integrationBun.serve HTTP and WebSocket server built innode:http servers, cluster workers, inspector for tracing
AI-related capabilitiesClaude Code ships as a Bun executable (Bun's statement)Type stripping on by default; no type checking
Lock-in riskLow: MIT, npm-compatible, runs Node projectsNone: MIT, runs on every platform
Vendor Bun → Node.js →

1. Both runtimes cost nothing, so the invoice arrives as labour

Bun is MIT. Node.js is MIT. Neither sells a paid tier, so the bill is engineer-hours on three meters: the release calendar, the compatibility surface and the native-module ABI.

For teams maintaining a Node service: as of 10 November 2026, both runtimes have no price.

For Bun 1.4, check whether your native addons have builds for NODE_MODULE_VERSION 147.

2. Node bills you on a date you did not choose

Node's release page reads like a work schedule:

MajorStatusKey date
v27Alphafirst released 29 Oct 2026
v26 LithiumLTSfirst released 5 May 2026
v25EOL31 Mar 2026
v24 KryptonLTSfirst released 6 May 2025
v22 JodLTSfirst released 24 Apr 2024
v20 IronEOL24 Mar 2026

Support window and release cycle:

  1. LTS "typically guarantees that critical bugs will be fixed for a total of 30 months" (Node's wording).
  2. Starting with v27, the cycle becomes annual: every major gets six months of Alpha, six of Current, then LTS.

Read it as a penalty table. It punishes the team that adopts a major and forgets it: v20 lived from 17 Apr 2023 to 24 Mar 2026, about 35 months.

If production still runs Node 20, plan a move to Node 24 or 26 LTS: Node 20 reached EOL on 24 March 2026.

3. Who should not pick Node for unbuilt TypeScript

Type stripping is on by default, stable since v25.2.0 / v24.12.0. Node executes erasable syntax without type checking; other syntax needs separate tooling.

// runs on Node 26 with no flags: every annotation here is erasable
type Host = string;
const host: Host = process.env.HOST ?? "localhost";
console.log(`binding ${host}`);

enum throws ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX.

Node 26 also refuses:

This meter punishes codebases built on enums and path aliases; for them, the build step stays.

4. Bun's own node:http count leaves 415 − 403 = 12 tests failing

Bun says it plainly: "Bun is not 100% compatible with Node.js yet." Bun's own 1.4 counts against the Node 26.3.0 suite:

ModuleBun 1.4 passesNot passing
node:http403 / 415415 − 403 = 12
node:fs349 / 358358 − 349 = 9
node:module68 / 9393 − 68 = 25
node:test_runner28 / 8181 − 28 = 53
node:inspector22 / 110110 − 22 = 88
node:sqlite18 / 1818 − 18 = 0

On node:http that is 12 ÷ 415 ≈ 2.9%, the failing 3%. Bun says 1.4 made 1,517 more Node tests pass.

The ABI tax: 1.4 moved the compatibility target from 24.3.0 to 26.3.0. NODE_MODULE_VERSION is now 147, so native addons built for Node 24 must be rebuilt.

Check required inspector APIs; module pass counts are not application coverage.

5. Who should not pick Bun: teams requiring missing APIs

Bun's compatibility docs name the gaps. Map each to a service you run:

AsyncLocalStorage context does not propagate into Worker/BroadcastChannel events in Bun.

6. Bun stays MIT after Anthropic's acquisition; check before migrating

Anthropic acquired Bun on 2 December 2025. Claude Code ships as a Bun executable (Bun's statement), and Bun's founder wrote then: "Today, Bun makes $0 in revenue." Bun stays MIT.

The acquisition changes who pays for Bun's roadmap. It does not change the licence, and it does not change the API surface you have to test.

Check today:

  1. List every .node addon in the tree and whether it has a build for NODE_MODULE_VERSION 147.
  2. Check required HTTP APIs, createHook, distinct async IDs, getPeerCertificate and SNICallback against Bun's gaps.
  3. Write down the EOL date of the Node major running in production.

Cost arithmetic at volume

These are computed from the published unit prices, not measured. Each row prints its own formula, so you can replace our assumption with your traffic and redo it.

Bun 1.4 node:http compatibility gap
415 tests − 403 passing = 12 failing; 12 ÷ 415 ≈ 2.9%
12 failing node:http tests, about 3% (Bun's own count; neither runtime has a price, so the unit is tests)
Debug-and-test loop gap in Bun 1.4
node:inspector 110 − 22 = 88; node:test_runner 81 − 28 = 53
Bun's own counts leave 88 inspector tests and 53 test-runner tests unpassed; check the APIs your debugger or test runner requires before migrating.
Node 20 EOL-to-LTS decision
17 Apr 2023 → 24 Mar 2026 ≈ 35 months from first release to EOL; this is not the LTS fix window
Move production off EOL Node 20 to Node 24 or 26 LTS; the documented 30-month LTS fix guarantee is a separate interval.
Native addon rebuild tax for Bun 1.4
N native addons × 1 rebuild each for NODE_MODULE_VERSION 147 (target moved 24.3.0 → 26.3.0)
Every addon built for Node 24 needs a new build before Bun 1.4 can load it

Decision matrix

Rows are the situation you are actually in. Pick the row before you read the pricing page again.

If this is youTakeBecause
HTTP service considering Bun after checking required server APIsBun only if required APIs are supported and the service passes its checks; otherwise retain NodeBun's own node:http count is 403 / 415; check unsupported server options, http.Server inheritance and listen(handle), not just the pass count.
Repo with native addons built for Node 24Node, until every addon has a build for NODE_MODULE_VERSION 147Bun 1.4 targets Node 26.3.0, so addons built for 24 do not load until rebuilt.
Production tracing agent requiring createHook or distinct async IDsNodeKeep Node if your tracing agent requires createHook or distinct async IDs: Bun documents the hook as a stub and async IDs as always 0.
TLS gateway requiring getPeerCertificate() or SNICallbackNodeBun's node:https lacks getPeerCertificate() and does not support SNICallback.
Signing service that needs secp256k1 or ed448 keysNodeBun's BoringSSL-backed node:crypto has no secp256k1 curve and no ed448 key type.
Still on Node 20 in productionNode 24 or 26 LTS, not a runtime switchv20 reached EOL on 24 March 2026, and an LTS move fixes that without adding Bun's compatibility gaps to the same sprint.
Healthy service on Node 22 Jod with no pain pointsNeither — stay putv22 is still LTS and was last updated 20 October 2026, so no date forces a move yet.
Internal scripts and CLIs that currently pull in a separate test runner, linter and formatterBunBun 1.4 ships bun test --parallel, bun lint, bun fmt and bun check in the same binary.

Code and configuration

Bun
// One binary replaces four dev dependencies:
// bun install, bun test, bun lint and bun fmt are the same executable.
import { Database } from "bun:sqlite";   // built in, no addon to compile
const db = new Database(":memory:");
db.run("create table t (id integer primary key, name text)");
// Here it breaks: a native addon built for Node 24 will not load,
// because Bun 1.4 reports NODE_MODULE_VERSION 147.
Node.js
// Node 26 strips types; it does not check them or transform them.
type Host = string;
const host: Host = process.env.HOST ?? "localhost";
console.log(`binding ${host}`);
// Here it breaks: an enum is not erasable, so Node throws
// ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX before your code runs.
enum Mode { Dev, Prod }

What you gain, what you give up

Bun

You gain
  • JavaScript, TypeScript, JSX and bundling from one executable, so no separate tsc, test runner or bundler
  • 1,517 more Node test-suite tests pass in 1.4, and node:sqlite passes 18 of 18 by Bun's own count
  • Bun's own hello.js benchmark: 5.1 ms vs 27.2 ms start-up on Linux, 14.6 MB vs 44.5 MB peak memory
  • MIT licensed after the Anthropic acquisition, with the Node compatibility target moved to 26.3.0
You give up
  • node:http passes 403 of 415 of Node's own tests, and http.Server does not extend net.Server
  • node:https lacks getPeerCertificate() and getCipher(), and SNICallback is unsupported
  • NODE_MODULE_VERSION 147 means addons built for Node 24 must be rebuilt
  • Bun's own memory table shows the Vite dev server at 233 MB vs 214 MB on Node

Node.js

You gain
  • A dated calendar: v26 Lithium and v24 Krypton are LTS, and LTS typically guarantees fixes for 30 months
  • Native addons are the default path, and ABI builds target the runtime you actually run
  • TypeScript type stripping runs with no build step for erasable syntax
  • Nothing to license, and commercial support exists through OpenJS partners after LTS ends
You give up
  • Type stripping refuses enum, .tsx, parameter properties, import aliases and tsconfig paths
  • TypeScript inside node_modules is refused outright
  • Parsing requires WebAssembly, or the parser throws ERR_WEBASSEMBLY_NOT_SUPPORTED
  • v20 and v25 both reached end of life in 2026, so the calendar forces migrations

Migration path

What switching actually takes

Moving to Bun starts with bun install reading the same package.json, but every native addon needs a build for NODE_MODULE_VERSION 147 before it loads, so the hook stampede is the first thing to schedule. Moving back is not automatic either: Bun's compatibility docs list the API gaps you will meet — getPeerCertificate(), SNICallback, async_hooks — and there is no tool that rewrites handlers around them. Run the service test suite under both runtimes before either direction, then keep the loser's addon builds around for a release or two.

Common questions

Does Node 26 type-check TypeScript?
No: type stripping performs no type checking, so a separate tool is still required. Decorators are a parser error, and --experimental-transform-types was removed in v26.0.0.
Is Bun faster than Node?
Bun's own hello.js benchmark puts Linux start-up at 5.1 ms for Bun 1.4 versus 27.2 ms for Node.js 26; these are vendor measurements, not independent ones. Separately, Bun's peak-memory figures under load, with 1,000,000 requests and 64 connections, put the Vite dev server at 233 MB on Bun versus 214 MB on Node, so Bun is not lighter everywhere.
Can I buy support for a Node major after LTS ends?
Not from the Node.js project itself. Commercial support past Maintenance LTS is sold by OpenJS Ecosystem Sustainability Program partners.
Does Bun's MIT licence cover everything in the binary?
No: Bun statically links JavaScriptCore/WebKit, which is LGPL-2. That is why Bun's licence file spells out relinking obligations.

Sources & verification

Prices and limits were read from these pages on 2026-11-10. Vendor marketing claims are quoted as claims. Anything derived is arithmetic on the numbers below.

https://bun.com/blog/bun-v1.4
https://bun.com/blog/bun-joins-anthropic
https://bun.com/docs/runtime/nodejs-compat
https://nodejs.org/en/about/previous-releases
https://nodejs.org/api/typescript.html

Keep reading

Docker vs Podman

Another open-source runtime where the licence sits on the developer tool, not the engine.

Prisma vs Drizzle

Two free libraries whose maintenance now depends on a vendor with a bill attached.

Try Bun → Explore Node.js →
Source review date recorded in this article: 2026-11-10. This is not a live price or checkout check. Prices can change. If a number here looks wrong, the vendor's own price sheet wins. Derived figures are arithmetic on published unit prices, not measured benchmarks.