# Deno vs Node.js vs Bun

This is a decision-by-dimension comparison, not a benchmark chart. All three runtimes evolve quickly: compatibility claims, default behavior, and performance conclusions can change between releases. This page only states what was verified against official sources on the date above.

## Dimension-by-dimension comparison

| Dimension | Deno 2 | Node.js | Bun |
| --- | --- | --- | --- |
| Engine and model | V8 + Rust; Web API first, URL imports, `Deno.serve` | V8 + libuv; `node:` built-ins, the ecosystem's reference point | JavaScriptCore + Zig; implements both Web APIs and Node APIs |
| Permission model | Deny by default; `--allow-*` scoped by host, path, and env var | Full access by default; optional `--permission` model (added in v20, no longer experimental since v23.5/v22.13), documented as a "seat belt," not a security boundary | Full access by default; this page could not verify an equivalent built-in permission model in official docs — check current Bun docs before deciding |
| TypeScript | Runs natively with full type checking via built-in `deno check` | Type stripping on by default (since v23.6/v22.18, marked stable in v25.2/v24.12); erasable syntax only, no type checking, no `.tsx` | Transpiles and runs TS directly; type checking is delegated to `tsc` (the official recommended `tsconfig` sets `noEmit`) |
| Package management and registries | Native `package.json`, `node_modules`, and npm workspaces; `npm:` and `jsr:` specifiers; `deno add/install/ci` | npm registry and `package.json` are the ecosystem baseline; pnpm/yarn via Corepack or the package manager's own installer (Corepack no longer ships with Node as of Node 25) | Compatible with `package.json`/`node_modules`; `bun install` is the built-in package manager |
| Toolchain | fmt, lint, check, test, bench, doc, and compile built in | `node:test` and `--watch` built in; formatting and linting come from the ecosystem | test, bunx, bundler, and single-file compilation built in |
| Node compatibility status | `node:`/`npm:` specifiers plus `package.json` support; details evolve, verify with real tests | The reference itself | Officially targets Node compatibility with a per-module status table: "If a package works in Node.js but doesn't work in Bun, we consider it a bug" |
| Ecosystem and hiring | Smaller ecosystem; npm compatibility lowers switching cost | Largest package ecosystem, hosting support, and hiring pool | Smaller ecosystem; npm compatibility lowers switching cost |
| Deployment shapes | Containers/VMs/serverless + Deno Deploy + `deno compile` single-file binaries | Containers/VMs/serverless with the broadest hosting support | Containers/VMs + `bun build --compile` single-file binaries |

## Performance: do not quote other people's benchmarks

This page lists no numbers. Public benchmarks are highly sensitive to hardware, versions, and workload shape, and vendor-published numbers usually pick favorable scenarios. Measure your own workload instead:

1. Pin runtime and dependency versions (record `deno --version`, `node --version`, `bun --version` in the report).
2. Run on the same machine and dataset; capture startup time, steady-state throughput, p50/p99 latency, and resident memory.
3. Separate microbenchmarks (JSON serialization, Hello World) from real paths (framework middleware, database drivers, TLS). The former rarely predicts the latter.
4. Measure startup-sensitive scenarios (CLIs, cold starts) separately from long-running services.
5. Archive results together with versions, OS/arch, and commands; rerun after upgrades before comparing.

## When to choose which

| Constraint | Leaning |
| --- | --- |
| Maintaining an existing Node production system; hiring, training, and hosting support matter most | Node.js |
| New project; TypeScript first; zero-config fmt/lint/test/compile; deny-by-default permission sandbox required | Deno |
| Publishing a TypeScript library for both Deno and Node consumers | Deno + JSR |
| Install and startup speed is critical, and you are willing to validate npm compatibility with real tests | Bun |
| Existing Node project, evaluating or migrating to Deno incrementally | Start with [Migrating from Node.js](/en/docs/migration/from-node) |

There is no universal answer. Treat the table as an elimination tool: first remove options that fail hard constraints (permissions, hosting, existing code, team experience), then benchmark what remains against your own workload.

<Callout type="warn" title="Verify compatibility claims per version">
"X is compatible with Y" is a version-sensitive claim. Bun's compatibility table tracks a specific Node version and is updated continuously, and Deno's Node compatibility details evolve across minor releases. Before committing, validate with your project's real dependencies and test suite — do not rely on any single comparison page, including this one.
</Callout>

Official sources: [Deno 2.0 release notes](https://deno.com/blog/v2.0), [Deno Node compatibility docs](https://docs.deno.com/runtime/fundamentals/node/), [Node.js TypeScript support](https://nodejs.org/api/typescript.html), [Node.js permission model](https://nodejs.org/api/permissions.html), [Bun Node.js compatibility table](https://bun.sh/docs/runtime/nodejs-apis), [Bun TypeScript docs](https://bun.sh/docs/runtime/typescript).
