Node.js vs Deno vs Bun: Database reads Performance

Mayank Choubey
Tech Tonic
Published in
4 min readMay 6, 2024

--

It’s been a while since I’ve looked at the performance battle between these technologies. The last such comparison was done more than six months (when Bun 1.0 was out). Since then, Node.js, Deno, (and especially) Bun has gone through a number of major and minor releases. There have been numerous requests to carry out some useful comparisons again.

This is the second article in this series. The first one was the usual hello world, where we found that Bun is about 2x and 1.5x faster than Node & Deno respectively.

In this article, we’ll walk towards a more real world scenario of database reads.

Scenario

HTTP framework

This time around, we’ll use a framework instead of the native HTTP server. I’ve chosen the fastest (& stable) framework known for each one:

  • Fastify (Node.js)
  • Hono (Deno)
  • Elysia (Bun)

There is another framework called ‘hyper express’ which is very fast, however its real-world application is unknown at this point. Fastify is a battle tested production grade framework, so will be using that one. Hono & elysia are known to be the fastest for Deno & Bun respectively.

Database interactions

For this application, records are read from a local Postgres database. I’m using Sequelize ORM to fetch DB records.

Application Logic

The application logic is as follows:

  • The application will extract a user email parameter out of the request body (JSON)
  • The application will query a Postgres database for extracted email
  • The application will return the user record in HTTP response

Application code

The application code is different for main & controller files, while the service and db files are the same for all.

This is an I/O intensive scenario. Let’s see who fares the best. Can Bun maintain its 2x lead over Node.js? Let’s find out.

Test setup

All tests have been executed on MacBook Pro M2 with 8+4 cores & 16G of RAM. The software versions are:

  • Node.js v22.1.0
  • Deno v1.43.1
  • Bun v1.1.7

All tests are executed using Bombardier test tool. The Bombardier tool has been modified to send a random email ID from a pre-populated list of 100K email IDs. This ensures that the application doesn’t keep reading the same record a million times.

The Postgres database is pre-populated with ~100K records. The table structure is as follows:

\d users
Table "public.users"
Column | Type | Collation | Nullable | Default
--------+----------------+-----------+----------+---------
email | character(500) | | not null |
first | character(50) | | not null |
last | character(50) | | not null |
city | character(50) | | not null |
county | character(50) | | not null |
age | smallint | | not null |
Indexes:
"users_pkey" PRIMARY KEY, btree (email)
select count(*) from users;
count
-------
99999
(1 row)

Results

Each test of 1M requests is carried out for 100 & 300 concurrent connections. Readings are taken for time taken, RPS, and latency. Additionally, readings are taken for CPU and memory usage. The cost of performance is as important as the performance.

The results in chart form are as follows:

Verdict

Before we start comparing them, let’s look at the first obvious difference from the hello world case. The first obvious difference is in the request per second efficiency, which has dropped for all. Here is a graph showing ‘hello world’ vs ‘database reads’ RPS difference:

As soon as we’re out of the world of ‘hello world’, the RPS takes a major hit. No more 100K or 200K RPS. Node.js goes from 95K to 14K, Deno goes from 120K to 15K, and Bun goes from 162K to 17K.

Now for this case (database reads), Bun still leads the show, though the winning margin is very little. Bun is ~18% faster than Node.js, and 13.4% faster than Deno. Bun’s CPU usage is comparable, while memory usage is on the higher side.

Just basing the conclusion on numbers, the winner would still be Bun.

Thanks for reading this article!

--

--