Three JavaScript runtimes, three philosophies, one decision. Node.js (v24 LTS, Krypton, Oct 2025) is the ecosystem default — every npm package, every cloud provider, every framework targets it first. Bun 1.3 (April 2026, MIT-licensed but Anthropic-acquired Dec 2025) is a Zig-based all-in-one toolchain that ships a runtime, package manager, bundler, and test runner in a single binary, optimized for raw throughput. Deno 2.7 (Feb 2026) is the security-first runtime from Node's original creator, with sandboxed permissions, native TypeScript, and the stable Temporal API. Pick one wrong and you spend a quarter migrating; pick one right and you delete a third of your devDependencies.
Pick Bun
For raw speed and DX
Greenfield apps, monorepos with slow installs, edge functions where cold start matters, teams who want zero-config TypeScript and a built-in test runner. Auto-loads .env with no flag.
Pick Deno
For security & TS-first
Code that runs untrusted input, edge platforms (Deno Deploy, Netlify Edge), one-off scripts, and organizations that have been bitten by supply-chain attacks. Sandboxed by default — no surprise file or network access.
Pick Node
For the safe boring choice
Production systems where boring is a feature, projects that depend on native addons, AWS Lambda non-edge, and any team where "we picked an alternative runtime" would be a headline in the postmortem. v24 LTS is supported until April 2028.
Bun vs Deno vs Node at a glance
| Bun 1.3 | Deno 2.7 | Node.js 24 LTS | |
|---|---|---|---|
| Released | Sep 2023 (1.0) | May 2018 (1.0) | May 2009 (0.0.1) |
| JS engine | JavaScriptCore (WebKit) | V8 | V8 |
| Built in | Zig | Rust | C++ |
| License | MIT | MIT | MIT |
| Backed by | Anthropic (Dec 2025) | Deno Land Inc. | OpenJS Foundation |
| Default permissions | Open | Sandboxed | Open (opt-in --permission) |
| Native TypeScript | Yes | Yes | Type-stripping only |
Auto-loads .env | Yes | --env-file required | --env-file required |
How fast is each runtime, really?
Synthetic "Hello World" benchmarks make Bun look like it lapped the field. Production benchmarks, where a request actually hits a database, mostly converge. Three numbers worth knowing in 2026:
AWS Lambda cold start (ms, lower is better)
Three-month production case study, equivalent handler. Bun reported 290ms vs Node's 940ms — a 69% improvement. No directly comparable Deno number was published in the same study; Deno Deploy is the Deno-native edge target. Source: Strapi, Bun vs Node.js benchmarks (2026).
HTTP throughput on the same Express-style handler (k requests/sec, higher is better)
Single process, no database, identical handler code on each runtime. Bun's native Bun.serve reaches ~68k req/s on the same test. Real apps with database round-trips converge to roughly 12k req/s on all three. Source: DEV Community three-way benchmark (2026); ByteIota production-grade comparison (2026).
Cold install of a 1,847-dependency monorepo (lower is better)
Empty cache, no lockfile reuse. Bun finishes in 47 seconds where npm takes 28 minutes — roughly 35× faster than npm and 5× faster than pnpm. deno install reads package.json as of 2.0; no directly comparable benchmark of deno install at this scale was published. Source: DEV Community (2026); Strapi (2026).
The honest read: Bun wins package install and cold start by margins large enough to feel in CI and in Lambda-style serverless. It wins synthetic HTTP throughput by 2–4×. But Strapi's production-grade URL shortener — routing, validation, database — measured Bun at 12,400 req/s versus Node's 12,000, a < 3% gap that disappears into noise. ByteIota independently reports all three converging at roughly 12k req/s once a database is in the request path. Deno lands between the two on HTTP — ahead of Node, behind Bun — while winning on TypeScript transpile cost (it transpiles natively, no tsc step).
How do Bun, Deno, and Node handle .env files?
This is the one place env.dev cares about most, and it's also where the three runtimes diverge most sharply. See the .env guide for full syntax rules; the runtime differences are below.
Bun — auto-load
# Just create .env
bun run server.tsBun reads .env, .env.local, and .env.{NODE_ENV} automatically. Values land on process.env, Bun.env, and import.meta.env. No flag, no dependency.
Deno — explicit
deno run \
--allow-env \
--env-file=.env \
server.tsDeno requires both --env-file to load and --allow-env to read. Access via Deno.env.get("PORT"). No env access without explicit permission — the security model is the point.
Node — flag, no dep
node \
--env-file=.env \
server.jsStable since Node 24.10 (originally landed in v20.6, Aug 2023). No more dotenv dependency for the basic case. --env-file-if-exists skips missing files silently.
--env-file is read before the permission model initializes, so .env bypasses --allow-fs-read. Deno's --env-file respects sandboxing. Bun has no permission model at all in 2026 — open by default, like Node without the --permission flag. If your threat model includes a malicious npm dependency reading .env, Deno is the only one of the three that defends by default.For Node-side specifics — the string-everything trap, NODE_ENV=production side effects, cross-platform pitfalls — see Node.js environment variables. For the parser-level rules every runtime quietly disagrees on (multi-line values, comments, quoting), see .env file syntax.
Feature parity matrix
| Capability | Bun 1.3 | Deno 2.7 | Node 24 |
|---|---|---|---|
| Run TypeScript without compile step | Native | Native | Strip-only |
| npm registry compatibility | Full | Full + JSR | Native |
| CommonJS (require) support | Yes | Via npm: | Native |
| ESM as default | Yes | Yes | Yes |
| Built-in test runner | bun test (Jest API) | deno test | node --test |
| Built-in package manager | bun install | deno install | npm |
| Built-in bundler | bun build | deno bundle (legacy) | No |
| Watch mode | bun --watch | --watch | --watch |
| Permission sandbox | None | Default-on | Opt-in --permission |
| Web standard fetch / Request / Response | Yes | Yes | Yes |
| Stable Temporal API | Behind flag | 2.7 stable | V8 14.5+ |
| Native SQL client (Postgres / SQLite) | Bun.SQL, bun:sqlite | node:sqlite via shim | node:sqlite (stable) |
| Compile to single binary | bun build --compile | deno compile | --experimental-sea-config |
Who uses each in production?
Adoption signals matter more than benchmarks because they tell you what survives a year of operational pain.
Bun
- Anthropic — uses Bun as core infra for Claude Code; led to the December 2025 acquisition.
- DigitalOcean App Platform — native Bun runtime support shipped 2025.
- Vercel & Cloudflare — both run Bun-built bundles in production edge environments.
Deno
- Slack — runs customer code in their automation platform on Deno; chose it specifically for the secure-by-default sandbox.
- The Guardian — audits accessibility and performance across 2.7M articles; Deno cited for TypeScript and security model.
- Plaid — migrated 100 services 5× faster with Deno tooling.
- Netlify Edge Functions — Deno-powered runtime.
Node.js
- Nearly everyone else — Netflix, LinkedIn, PayPal, Walmart, Uber, NASA. The default JavaScript runtime since 2009.
- AWS Lambda, Google Cloud Functions, Azure Functions — first-class Node support; Bun and Deno are still custom-runtime layers.
- Every CI/CD pipeline — every action runner, every Dockerfile
node:24-alpinebase image.
What changed since the 2024 hype cycle?
Each runtime addressed its biggest 2024 weakness. The differences that mattered then mostly don't anymore.
- Node 20.6 (Aug 2023) shipped
--env-file, killing the most common reason to install dotenv. Node 24 LTS made the permission model stable as--permission, a feature Deno had had since day one. - Deno 2.0 (Oct 2024) reversed the early-Deno bet against npm and shipped first-class
package.jsonsupport. Deno 2.7 (Feb 2026) addednpm:overrides, JSR specifiers inpackage.json, and the stable Temporal API. The "you have to rewrite for Deno" objection is gone. - Bun 1.2 (Jan 2025) swapped its binary lockfile for the text-based
bun.lock, fixing the diff-review problem that blocked production adoption. Bun 1.3 (Oct 2025) added Postgres viaBun.SQL, a Redis client, and zero-config frontend. Anthropic acquired the project in December 2025; the runtime is still MIT and open source, but now has corporate backing. - All three converged on web standards — global
fetch,Request,Response,URLPattern,Web Crypto, and the WinterCG minimum surface. Code that uses standard APIs runs on all three with no changes.
How do you migrate from Node to Bun or Deno?
Both are designed as drop-ins, with caveats. The bigger your app's exposure to native addons (sharp, node-canvas, native bcrypt, custom NAPI modules), the more friction.
Node → Bun
# 1. Install (curl one-liner or npm i -g bun)
curl -fsSL https://bun.sh/install | bash
# 2. Migrate lockfile
bun install
# Reads existing package-lock.json or pnpm-lock.yaml,
# writes bun.lock.
# 3. Run
bun run server.ts # replaces `node` and `tsx`
bun test # replaces jest/vitest in many casesWatch out for: native modules (most work, some don't); Worker threads (different shape); process.binding and other private APIs.
Node → Deno
# 1. Install
curl -fsSL https://deno.land/install.sh | sh
# 2. Use existing package.json or migrate
deno install # reads package.json
# 3. Run with explicit permissions
deno run \
--allow-net \
--allow-env \
--allow-read \
--env-file=.env \
server.tsWatch out for: --allow-* flags everywhere until you tighten them; some packages need npm: prefix; Deno-specific globals (Deno.env) must be added if you want to use the security model fully.
Which is best for serverless / edge?
Cold start dominates this answer. Bun cold-starts at ~290ms in the AWS Lambda case study above, versus Node's ~940ms — a 3.2× gap that translates to lower p99 latencies for low-traffic functions. Deno is the runtime behind Netlify Edge Functions and Deno Deploy, where its instant-start design is the entire product. Node is still the default on Lambda, Cloud Functions, and Azure Functions; Bun and Deno require custom runtime layers on AWS as of May 2026.
The Cloudflare Workers angle is different: Workers run on V8 isolates, not Node, so the question becomes "does my code use Node-only APIs?" — increasingly answered by the nodejs_compat compatibility flag. env.dev itself runs on a Cloudflare Worker.
When should you stay on Node?
Boring is a feature. Pick Node when:
- You depend on native addons that haven't been ported (some image processing, hardware drivers, legacy NAPI).
- Your CI/CD, container base images, and IaC modules are all standardized on
node:— switching costs more than it saves. - Your team has on-call rotation and "we picked an alternative runtime" would be the second sentence of every postmortem.
- You ship libraries that need to work for the broadest install base — Node is the lowest-common-denominator target.
- You're already happy with
npm/pnpm,tsx/ts-node, andvitest; the all-in-one toolchain pitch isn't worth the migration to you.
Key takeaways
- Bun wins on raw throughput, install speed, and zero-config DX — and it auto-loads
.env. - Deno wins on security (sandboxed by default), TypeScript ergonomics, and edge runtime story.
- Node wins on ecosystem, tooling, hiring, cloud platform support, and "nobody got fired for picking Node."
- The runtimes have converged on web standards — code using
fetch/Request/Responseports across all three with minor friction. - For
.env: Bun auto-loads, Deno requires--env-file+--allow-env, Node requires--env-fileonly. None auto-load on a bare invocation except Bun. - Real-world HTTP throughput gaps narrow to < 5% once a database is in the request path; the synthetic 3× advantage rarely survives production.
Sources
- Strapi — Bun vs Node.js in 2026: Benchmarks & Migration Guide — source for the 290ms / 940ms AWS Lambda cold start, 52k vs 13k req/s synthetic throughput, the 12,400 vs 12,000 URL shortener real-world figure, and the 1,847-dependency monorepo install benchmark.
- DEV Community — Bun vs Deno vs Node.js in 2026: Benchmarks, Code, and Real Numbers — source for the three-way 52k / 29k / 14k req/s Express comparison and the 68k req/s native
Bun.servefigure. - ByteIota — Bun Runtime Production Guide 2026: Speed vs Stability — confirms convergence at ~12k req/s once databases are in the request path; cross-checks 5–15ms vs 60–120ms startup numbers.
- Deno blog — 2.7 release (Feb 2026) — Temporal API stabilization, npm overrides in
package.json, JSR specifiers, Windows on ARM builds. - Bun releases on GitHub — source for Bun 1.3.x feature dates (1.3 zero-config frontend, 1.3.10 Windows ARM, 1.3.12 Apr 2026).
- Node.js v24.0.0 release notes and the Permissions docs — source for the LTS date (Oct 2025), V8 13.6, Undici 7, stable
--permissionflag. - Deno blog — How Slack used Deno and Deno in production — source for the Slack, Plaid, and Guardian adoption claims.