Architecture · October 28, 2026 · Daniel Murillo
Node.js vs Bun vs Deno: how to choose a backend runtime in 2026
Do not choose only by requests/s. Ecosystem, compatibility, operations, and the performance of your real application.
Do not choose a runtime only from a requests-per-second table. Evaluate the ecosystem you need, dependency compatibility, production operations, and the performance of your real application.
1. The right question is not “which is the fastest?”
Node.js, Bun, and Deno run JavaScript and TypeScript, but they were born with different priorities:
- Node.js: compatibility, maturity, ecosystem, and operations proven at scale. In October 2026, Node.js 26 enters Active LTS; 24 moves to maintenance.
- Bun: startup speed, integrated tooling, and performance; it aims to be a runtime and also a toolbox. Bun 1.4 targets Node 26 compatibility and documents a major runtime rewrite.
- Deno: permission-based security, web standards, direct TypeScript, and integrated tooling. Deno 2.9 improves HTTP startup/memory and adds
deno desktopplus better reading of npm/pnpm/Yarn/Bun lockfiles.
Today the choice is no longer reduced to “Node is the only one ready for production.” Bun and Deno have advanced a lot in compatibility and capabilities. But it is also incorrect to conclude they are already identical substitutes: differences appear in native dependencies, Node APIs, observability tools, deployments, and specific behaviors.
The decision should answer these questions:
- What libraries does the project need and which APIs do they use?
- Which frameworks, drivers, and observability tools will run?
- How much do startup time, memory, or throughput matter?
- On which platform will it be deployed?
- How costly would it be to investigate and resolve an incompatibility?
- Does the team need conservative stability or want to take advantage of new tools?
2. Quick comparison
| Dimension | Node.js | Bun | Deno |
|---|---|---|---|
| JavaScript engine | V8 | JavaScriptCore | V8 |
| Historical priority | Ecosystem and compatibility | Performance and integrated tools | Security, web standards, and DX |
| TypeScript | Supported directly in recent versions for erasable syntax; type-checking with separate tools | Direct execution; transpiles, but does not replace tsc type-checking | Direct execution and integrated deno check |
| Packages | npm, pnpm, Yarn | bun install, plus npm package compatibility | deno add, JSR, and npm packages |
| Node APIs | Main reference | Broad compatibility, but not total | Growing compatibility; some APIs and cases still need verification |
| Permission-based security | No equivalent permission sandbox enabled by default | Not its central proposal | Explicit permissions for files, network, environment, and other resources |
| Integrated tools | Broad external ecosystem | Runtime, package manager, test runner, bundler, and transpiler | Runtime, package manager, formatter, linter, test runner, and type-checker |
| Historical ecosystem | The broadest and most proven | Growing, with emphasis on modern TypeScript projects | Smaller than Node, with increasing npm compatibility |
| Typical best fit | Conservative production and systems with many dependencies | APIs and tools where performance and DX matter | Services focused on security, web standards, and integrated tooling |
Important: “running TypeScript” is not the same as “checking types.” Bun and Node can transpile or strip annotations, but static checking should still be part of the pipeline when TypeScript is used.
3. Node.js: the reference for ecosystem and predictability
Node.js does not need to be the fastest runtime in every microbenchmark to be an excellent decision. Its central advantage is the combination of maturity, compatibility, and accumulated operational knowledge.
Advantages
- Extensive ecosystem: large number of libraries, SDKs, integrations, drivers, and observability tools.
- Compatibility: many packages are developed and tested first against Node.js.
- Known operations: consolidated patterns for containers, processes, profiling, logs, metrics, and deployments.
- Mature backend frameworks: Express, Fastify, NestJS, AdonisJS, and others.
- Support and hiring options: it is easy to find Node.js experience in teams and organizations.
- V8: an engine with years of optimization for general-purpose JavaScript workloads.
Disadvantages
- Fragmented tooling: the runtime, package manager, test runner, formatter, linter, and bundler are usually separate tools.
- Startup and tooling: for small scripts or CLIs, startup and the development cycle can feel heavier than in Bun.
- Maturity also implies legacy: old projects can drag along CommonJS, unmaintained dependencies, or complex configurations.
- Not everything is solved by the runtime: real speed depends on the framework, the code, database queries, and infrastructure.
When to choose Node.js
Node.js is the most conservative option when the project depends on critical libraries, vendor SDKs, APM, security agents, native modules, or integrations you cannot easily replace. It is also a reasonable choice when the team already has experience operating Node and there is no business metric that justifies a change.
Do not confuse “better known” with “always better”: if a new application can use web standards and has compatible dependencies, Bun or Deno can reduce friction and offer real benefits.
4. Bun: performance and integrated tools
Bun was built with the idea of improving both execution and the development experience. It uses JavaScriptCore and is implemented largely in Zig. It includes a runtime, package manager, test runner, transpiler, and bundler.
Advantages
- Fast startup: attractive for scripts, CLIs, build tasks, and workloads where processes are created frequently.
- TypeScript and JSX without extra configuration: convenient for local development and tools.
- Integrated package manager:
bun installcan speed up installs in certain projects and environments. - Integrated HTTP server and WebSockets:
Bun.serve()offers a direct path for network services. - npm and Node compatibility: lets you run many existing projects and frameworks without rewriting them.
- Good performance potential: its public benchmarks show advantages in some HTTP, TLS, query, and WebSocket scenarios.
Disadvantages and risks
- Compatibility does not mean identity: a package that depends on a Node-specific detail, a native module, or a partially implemented API may behave differently.
- The framework matters: using Express on Bun is not the same as using Bun’s native server. The result depends on where time is spent.
- Operations must be validated: you need to test APM, tracing, profiling, workers, serverless deployments, and critical modules on the specific version chosen.
- Separate type-checking: direct TypeScript execution does not replace
tsc --noEmitor pipeline checks. - Less operational history than Node: although the project has matured, organizations with strict requirements may prefer to adopt it gradually.
Frameworks and libraries with Bun
Options worth evaluating:
- Elysia: TypeScript framework designed around Bun, with ergonomics and performance as central goals.
- Hono: web-standards-based framework that supports Bun, Node.js, and Deno, among other environments.
- Express: many projects work thanks to Node API compatibility; the real application must be tested.
- NestJS: it is possible to experiment with Bun as a runtime, but you must validate adapters, dependencies, build scripts, and any specific integration. Do not assume full compatibility just because the project compiles.
- Fastify: the framework is oriented toward Node.js; if you intend to run it with Bun, explicitly validate the plugins and APIs used.
When to choose Bun
Bun is a strong option for a new TypeScript API, internal tools, scripts, and services where startup or throughput have measurable value. It is also interesting in monorepos to speed up installs and development tasks.
A prudent strategy is to run compatibility tests and a representative load test first. If the service depends on a large number of native packages or production integrations, start with a bounded service instead of migrating the entire platform at once.
5. Deno: security, web standards, and an integrated experience
Deno was born with a different stance: explicit permissions, web standards, and a coherent experience for running, checking, testing, and formatting code. Its ecosystem has evolved: Deno 2 lets you use a growing number of npm packages and projects originally developed for Node.js.
Advantages
- Explicit permissions: code does not automatically get unrestricted access to files, network, or environment variables when run with Deno’s permission model.
- Direct TypeScript: you do not need to configure an external transpiler to run common TypeScript.
- Integrated tools:
deno fmt,deno lint,deno test, anddeno checkreduce the number of pieces to configure. - Web standards: APIs such as
fetch,Request,Response,URL, and streams help share patterns across environments. - Evolving npm compatibility: Deno 2 supports
package.json, npm packages, and more Node APIs than in early versions. - Good performance on some HTTP workloads: recent versions have improved throughput, startup, and memory in benchmarks published by the team.
Disadvantages and risks
- Partial Node compatibility: coverage has advanced a lot, but there are still APIs, native modules, and tools that may require adjustments.
- Smaller ecosystem: fewer examples, accumulated experience, and some specific integrations than in Node.js.
- Operational permission model: it is a security advantage, but requires defining permissions correctly in scripts, CI, and production.
- Not all libraries are designed for web standards: some assume Node’s module system, paths, or behavior.
- You must test the real deployment: especially with native packages, build tools, tracing, and libraries that inspect
node_modules.
Frameworks and libraries with Deno
- Hono: works on Deno, Bun, and Node.js; an interesting option for sharing code across runtimes.
- Fresh: framework associated with the Deno ecosystem, designed for web applications and server rendering.
- Oak: middleware framework inspired by Koa, traditional in Deno projects.
- Express and Node frameworks: Deno 2 can run many npm packages, but each application must validate its dependencies and behavior.
When to choose Deno
Deno makes sense when permission-based security, web APIs, and integrated tooling are an important part of the decision. It can also be attractive for new, bounded services that use Hono or another layer compatible with web standards.
For an application that depends on many Node libraries, run a compatibility test before making it the default platform. Compatibility is advancing, but a test-coverage figure does not guarantee that every package in your project will work.
6. Frameworks: separate runtime from framework
One of the most common mistakes when comparing runtimes is comparing Bun.serve() against Express, or a minimal Deno HTTP server against a full NestJS application.
They are different layers:
- Runtime: executes JavaScript, manages system APIs, and provides network capabilities.
- HTTP server: receives connections and builds responses.
- Framework: adds routing, middleware, validation, dependency injection, and conventions.
- Application: adds authentication, serialization, data queries, business rules, and observability.
A practical guide:
| Framework / style | Node.js | Bun | Deno | Considerations |
|---|---|---|---|---|
node:http / native server | Native | Widely compatible Node APIs; validate details | Growing node: compatibility | Low-level comparison, not productivity |
| Express | Native | Many cases work; test dependencies | Compatible with many projects via npm, with validation | Popularity does not imply the best throughput |
| Fastify | Native | Validate plugins and specific APIs | Not the main target; validate carefully | Very good reference point on Node |
| NestJS | Native | Possible with adapter and dependency validation | Possible via Node compatibility; review each integration | Architecture and modules can weigh more than the runtime |
| Hono | Yes, with adapter | Yes | Yes | Good portable option based on web standards |
| Elysia | Not its main environment | Designed for Bun | Not its main environment | Interesting if you decide to adopt Bun explicitly |
| Fresh | Not its main environment | Not its main environment | Deno ecosystem | More oriented to web apps than to being only an API microframework |
| Oak | Can run with adaptations; not its focus | Review compatibility | Traditional in Deno | Evaluate if you want to maintain an existing Deno project |
Recommendation: if portability matters, prioritize standard web APIs and reduce dependencies that access runtime details directly. If you need NestJS, Fastify-specific plugins, or an SDK that only officially supports Node, do not base the decision on a test with an empty endpoint.
For the NestJS / Spring Boot / FastAPI comparison (framework layer, not runtime), see NestJS, Spring Boot, and FastAPI.
7. Current benchmarks: what they show and what they do not
The numbers below are a sample of public benchmarks consulted in October 2026. They do not form a single controlled competition: each table uses different loads, hardware, versions, and configurations. That is why they must be interpreted within each test, not mixed to declare an absolute winner.
7.1 Native HTTP: minimal endpoint
Bun’s documentation publishes a comparison of a minimal server that returns text. In that historical test, Bun reports around 160 000 requests/s versus about 64 000 for Node 16, approximately 2.5× more. It is a useful data point for understanding the potential of Bun’s native server, but it is not a comparison with modern Node or a real API.
Source: Bun — HTTP server benchmarks
7.2 HTTP server and realistic load published by Deno
Deno 2.9 published a test with concurrency 100, including a text response, a 1 MiB body, and a “realworld” load that receives JSON with a bearer token and returns JSON. For the realistic load, the team reported an improvement from 56.8k to 72.4k requests/s versus Deno 2.8, approximately 1.27×; reported memory use went from 142 MB to 64 MB.
This measures Deno’s evolution between versions; it does not prove that Deno is faster than Bun or Node in every application.
Source: Deno 2.9 — Performance
7.3 Comparison published by Bun: Express over HTTPS
Bun publishes a test of Express 5.2.1 with TLS 1.3 and bombardier, using Linux x64 and an AMD EPYC CPU. The medians of three reported runs are:
| Runtime | Requests/s | Peak RAM |
|---|---|---|
| Bun 1.4 | 48 243 | 105 MB |
| Node.js 26.7 | 25 181 | 142 MB |
| Deno 2.9.5 | 19 243 | 176 MB |
In that configuration, Bun records approximately 1.9× Node’s throughput and 2.5× Deno’s. However, the table comes from Bun’s site, and it is worth reviewing the reproduction code, versions, and dependency behavior before generalizing.
Source: Bun — benchmarks
7.4 PostgreSQL query: the driver also changes the result
In another test published by Bun, queries are run against local PostgreSQL: SELECT of 100 rows, 100 concurrent queries, and 100 000 total queries. Bun.sql is compared with postgres.js 3.4.9 on Linux x64 over AMD EPYC.
| Runtime / driver | Queries/s | Peak RAM |
|---|---|---|
Bun 1.4 (Bun.sql) | 20 243 | 80 MB |
Deno 2.9.5 (postgres.js) | 10 406 | 181 MB |
Node.js 26.7 (postgres.js) | 10 000 | 168 MB |
This test does not isolate only the runtime: Bun uses its integrated SQL API, while Deno and Node use postgres.js. It is a comparison of the runtime + database client + configuration set, not a pure JavaScript execution test.
Source: Bun — benchmarks
7.5 Script startup
Bun documents a “Hello World” script benchmark on Linux with these values:
| Runtime | Reported time |
|---|---|
| Bun | 5.2 ms |
| Node.js | 25.1 ms |
It is a small, specific startup test. It is not equivalent to the startup time of an application that imports NestJS, an ORM, a cloud SDK, and several modules.
Source: Bun Runtime docs
What conclusion can we draw?
- Bun shows relevant advantages in several published tests, especially startup and certain HTTP and integrated-tooling scenarios.
- Deno has improved a lot in startup, throughput, and memory use in recent versions.
- Node.js remains competitive and can be the best overall option when platform compatibility and stability weigh more than a one-off performance difference.
- Results change with the load. Runtime, framework, database driver, TLS, serialization, logging, and observability alter the result.
- Projects’ own tests are useful, but not neutral. To decide, reproduce them and add a test of the real application.
Do not use numbers from different tables as if they were all measured on the same machine. Do not extrapolate the result of an empty endpoint to an API with queries, validations, authentication, and access to external services.
8. How to make a useful comparison in your project
Instead of chasing a single number, design a repeatable test.
Equalize the conditions
- Use concrete stable versions of each runtime.
- Run the same business code and the same framework when compatible.
- Keep hardware, operating system, CPU and memory limits, and network configuration the same.
- Use the same database, dataset, connection pool, and caching strategy.
- Test with and without TLS, if TLS is part of the real architecture.
- Repeat each scenario several times and report medians and variability.
- Separate startup tests, sustained throughput, and behavior under spikes.
Measure more than requests per second
| Metric | Why it matters |
|---|---|
| Throughput | Requests completed per second |
| Latency p50, p95, and p99 | The average can hide slow queues |
| Resident memory (RSS) | Especially with multiple replicas |
| CPU per request | Useful for sizing infrastructure |
| Cold start | Important for serverless, jobs, and CLIs |
| Errors and timeouts | High throughput does not help if errors rise |
| Stability under sustained load | Not only a few-second burst |
| Cost per traffic volume | Economic impact, not only the technical result |
Three recommended scenarios
Scenario A — Minimal HTTP: lets you measure the approximate ceiling of the server and runtime.
Scenario B — Representative API: includes routing, validation, serialization, authentication, and a real database query.
Scenario C — Simulated production: adds TLS, logging, tracing, CPU/memory limits, and a sustained load with latency percentiles.
To generate load you can use tools such as oha or bombardier. Check that the generator is not the bottleneck. Bun’s own documentation warns that a load client that is too slow can distort the results of a fast server.
Reference: Bun — Benchmarking
9. Migration: do not change runtime only because of a table
If you already have a Node.js application, a migration can cost more than the benefit.
Checklist before changing
- Run unit, integration, and end-to-end tests on the candidate runtime.
- Inventory packages that use
node:APIs, CommonJS, native addons, or direct system access. - Validate ORM, database driver, authentication, hashing, cryptography, and cloud SDKs.
- Test OpenTelemetry, APM, profiling, logs, and metrics.
- Verify Docker, health checks, shutdown signals, workers, and process handling.
- Run load tests with the real traffic pattern.
- Define a rollback strategy.
- Confirm that improvements hold in the environment where it will actually be deployed.
An adoption strategy with limited risk
- Keep the current runtime as the reference.
- Choose a small, low-criticality service.
- Create an automated compatibility test.
- Measure performance and resource use with comparable loads.
- Deploy gradually and monitor errors and latency.
- Expand adoption only when the benefit is observable.
It is not necessary to migrate the entire organization to a single runtime. A platform can keep Node.js for services with mature dependencies and use Bun or Deno in components where their advantages are clear, as long as the team can operate that diversity without increasing complexity too much.
10. Decision matrix
| If your priority is… | First option to evaluate | Why |
|---|---|---|
| Maximum compatibility with packages and SDKs | Node.js | It is the main ecosystem reference |
| Minimize risk on a large established platform | Node.js | Less uncertainty if all tooling is already proven |
| Fast startup and integrated tooling | Bun | Designed to reduce friction and improve startup |
| High throughput on a new service | Bun and Deno, along with Node | Representative benchmark before choosing |
| Security with explicit permissions | Deno | The permission model is a central feature |
| Use standard web APIs across runtimes | Deno or Bun; Hono as a portable framework | Reduces coupling to Node-specific APIs |
| Build an API with Hono for several platforms | Any of the three | Hono supports Node, Bun, and Deno |
| Use NestJS and a large number of integrations | Node.js as the base; test alternatives | Project compatibility and tooling weigh more |
| Scripts, tests, bundling, and integrated install | Bun or Deno | Fewer separate tools to configure |
| Adopt the technology with the smallest change curve for a Node team | Node.js | Fewer new concepts and operational differences |
This matrix does not mean the other options are incapable. It points to where the initial advantage usually sits and what to validate first.
11. Final recommendation
There is no universal winner.
I would choose Node.js for a large business platform, with many dependencies, third-party integrations, mature observability, and a high cost for incompatibility. Its value is not only speed: it is the predictability of the whole ecosystem.
I would evaluate Bun for new TypeScript services, high-volume APIs, development tools, and monorepos where startup, install, and performance are measurable advantages. I would adopt it after validating critical dependencies and the production environment.
I would evaluate Deno when the permission model, standard web APIs, and tool integration are an important part of the design. Hono can help keep the code more portable. Before migrating a large Node application, I would check the exact APIs and dependencies.
The right architecture decision balances performance, compatibility, security, team experience, operating costs, and maintenance. If Bun delivers 30% more throughput on your real load and introduces no incompatibilities, it can be a great choice. If a migration increases risk and only improves a synthetic endpoint, it probably is not worth it. And if Deno better solves security and deployment requirements, that advantage can be worth more than any speed ranking.
The practical rule: benchmark your application, not the runtime’s marketing.
In this series
- Node.js: why it remains a solid bet
- Bun: is it really faster than Node.js?
- Deno: security, TypeScript, and tools
- Final comparison: Node.js vs Bun vs Deno
Related reading
- NestJS, Spring Boot, and FastAPI
- Monorepo: Bun, pnpm, and Nx
- Benchmarks and architecture decisions
- Tool: which runtime fits you
- Tool: which frontend fits you
- Tool: which backend fits you
- Tool: which API protocol fits you
References
Official documentation
- Node.js — Releases and support schedule
- Bun — Runtime
- Bun — Node.js compatibility
- Bun — HTTP server and benchmarks
- Bun — How to benchmark
- Deno — Node.js and npm compatibility
- Deno 2.9 — performance improvements
- Hono — documentation and supported runtimes
- Fastify — framework benchmarks
How to read these sources
Official pages are useful for knowing capabilities, compatibility limits, and reproducible tests. Benchmarks published by the runtime itself should be read as evidence of a particular scenario, not as an independent and definitive ranking. Before a production decision, record exact versions, repeat the tests, and publish the configuration used along with the results.