Daniel Murillo
Index

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 desktop plus 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:

  1. What libraries does the project need and which APIs do they use?
  2. Which frameworks, drivers, and observability tools will run?
  3. How much do startup time, memory, or throughput matter?
  4. On which platform will it be deployed?
  5. How costly would it be to investigate and resolve an incompatibility?
  6. Does the team need conservative stability or want to take advantage of new tools?

2. Quick comparison

DimensionNode.jsBunDeno
JavaScript engineV8JavaScriptCoreV8
Historical priorityEcosystem and compatibilityPerformance and integrated toolsSecurity, web standards, and DX
TypeScriptSupported directly in recent versions for erasable syntax; type-checking with separate toolsDirect execution; transpiles, but does not replace tsc type-checkingDirect execution and integrated deno check
Packagesnpm, pnpm, Yarnbun install, plus npm package compatibilitydeno add, JSR, and npm packages
Node APIsMain referenceBroad compatibility, but not totalGrowing compatibility; some APIs and cases still need verification
Permission-based securityNo equivalent permission sandbox enabled by defaultNot its central proposalExplicit permissions for files, network, environment, and other resources
Integrated toolsBroad external ecosystemRuntime, package manager, test runner, bundler, and transpilerRuntime, package manager, formatter, linter, test runner, and type-checker
Historical ecosystemThe broadest and most provenGrowing, with emphasis on modern TypeScript projectsSmaller than Node, with increasing npm compatibility
Typical best fitConservative production and systems with many dependenciesAPIs and tools where performance and DX matterServices 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 install can 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 --noEmit or 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, and deno check reduce 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 / styleNode.jsBunDenoConsiderations
node:http / native serverNativeWidely compatible Node APIs; validate detailsGrowing node: compatibilityLow-level comparison, not productivity
ExpressNativeMany cases work; test dependenciesCompatible with many projects via npm, with validationPopularity does not imply the best throughput
FastifyNativeValidate plugins and specific APIsNot the main target; validate carefullyVery good reference point on Node
NestJSNativePossible with adapter and dependency validationPossible via Node compatibility; review each integrationArchitecture and modules can weigh more than the runtime
HonoYes, with adapterYesYesGood portable option based on web standards
ElysiaNot its main environmentDesigned for BunNot its main environmentInteresting if you decide to adopt Bun explicitly
FreshNot its main environmentNot its main environmentDeno ecosystemMore oriented to web apps than to being only an API microframework
OakCan run with adaptations; not its focusReview compatibilityTraditional in DenoEvaluate 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:

RuntimeRequests/sPeak RAM
Bun 1.448 243105 MB
Node.js 26.725 181142 MB
Deno 2.9.519 243176 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 / driverQueries/sPeak RAM
Bun 1.4 (Bun.sql)20 24380 MB
Deno 2.9.5 (postgres.js)10 406181 MB
Node.js 26.7 (postgres.js)10 000168 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:

RuntimeReported time
Bun5.2 ms
Node.js25.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

  1. Use concrete stable versions of each runtime.
  2. Run the same business code and the same framework when compatible.
  3. Keep hardware, operating system, CPU and memory limits, and network configuration the same.
  4. Use the same database, dataset, connection pool, and caching strategy.
  5. Test with and without TLS, if TLS is part of the real architecture.
  6. Repeat each scenario several times and report medians and variability.
  7. Separate startup tests, sustained throughput, and behavior under spikes.

Measure more than requests per second

MetricWhy it matters
ThroughputRequests completed per second
Latency p50, p95, and p99The average can hide slow queues
Resident memory (RSS)Especially with multiple replicas
CPU per requestUseful for sizing infrastructure
Cold startImportant for serverless, jobs, and CLIs
Errors and timeoutsHigh throughput does not help if errors rise
Stability under sustained loadNot only a few-second burst
Cost per traffic volumeEconomic 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

  1. Keep the current runtime as the reference.
  2. Choose a small, low-criticality service.
  3. Create an automated compatibility test.
  4. Measure performance and resource use with comparable loads.
  5. Deploy gradually and monitor errors and latency.
  6. 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 evaluateWhy
Maximum compatibility with packages and SDKsNode.jsIt is the main ecosystem reference
Minimize risk on a large established platformNode.jsLess uncertainty if all tooling is already proven
Fast startup and integrated toolingBunDesigned to reduce friction and improve startup
High throughput on a new serviceBun and Deno, along with NodeRepresentative benchmark before choosing
Security with explicit permissionsDenoThe permission model is a central feature
Use standard web APIs across runtimesDeno or Bun; Hono as a portable frameworkReduces coupling to Node-specific APIs
Build an API with Hono for several platformsAny of the threeHono supports Node, Bun, and Deno
Use NestJS and a large number of integrationsNode.js as the base; test alternativesProject compatibility and tooling weigh more
Scripts, tests, bundling, and integrated installBun or DenoFewer separate tools to configure
Adopt the technology with the smallest change curve for a Node teamNode.jsFewer 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

  1. Node.js: why it remains a solid bet
  2. Bun: is it really faster than Node.js?
  3. Deno: security, TypeScript, and tools
  4. Final comparison: Node.js vs Bun vs Deno

Related reading

References

Official documentation

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.