DEV Community

Костя Третяк
Костя Третяк

Posted on

A quick overview of Bun's basic features and how it compares to Node.js

Bun is a JavaScript runtime, positioned by its author as a set of ready-to-use tools "out of the box" provided along with the JavaScript runtime: this includes a package manager, a bundler, and a test runner. Additionally, the author strives to offer strong TypeScript support so that there’s no need to compile TypeScript files into JavaScript files. It's been almost a year since the first version of Bun was released. In this short post, I will examine how well the claimed features align with reality and the performance it delivers.

Installing Bun

As shown on Bun's main page, on Linux or macOS, it can be installed as follows:

curl -fsSL https://bun.sh/install | bash
Enter fullscreen mode Exit fullscreen mode

It can be upgraded to the next stable version with:

bun upgrade --stable
Enter fullscreen mode Exit fullscreen mode

Cloning the Repository with Benchmark Code

In this article, we will use the code that can be found in my repository. Clone it, navigate to the new directory, and install dependencies:

git clone https://github.com/KostyaTretyak/bun-vs-node.git
cd bun-vs-node
bun install
Enter fullscreen mode Exit fullscreen mode

Additionally, install the wrk benchmarking utility on your computer.

Comparing the Speed of Bun's Native Web Server and Node.js

Node.js on single process

First, let's see what Node.js shows, and then compare these results with Bun benchmarks. So, in the first terminal, run the node.mjs file:

node node.mjs
Enter fullscreen mode Exit fullscreen mode

On my machine, the cold start takes about 5ms.

Now, in the second terminal, run the benchmark:

wrk -H 'Connection: keep-alive' --latency -d 5 -c 256 --timeout 8 -t 4 http://localhost:3000/plaintext
Enter fullscreen mode Exit fullscreen mode

This command makes requests in four threads, with a concurrency of 256, for a duration of 5 seconds. On my machine, the average result is as follows:

Running 5s test @ http://localhost:3000/plaintext
  4 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    73.32ms  222.54ms   1.83s    92.72%
    Req/Sec     4.50k   665.94     6.39k    76.50%
  Latency Distribution
     50%   13.74ms
     75%   14.93ms
     90%   79.47ms
     99%    1.23s 
  89513 requests in 5.02s, 16.39MB read
Requests/sec:  17846.79
Transfer/sec:      3.27MB
Enter fullscreen mode Exit fullscreen mode

So, about 17 thousand requests per second.

Node.js with cluster mode

Now let's try using the cluster mode. To do this, go back to the first terminal, stop the process by pressing Ctrl+C, and run the following:

node node-cluster.mjs
Enter fullscreen mode Exit fullscreen mode

On my machine, it has 4 cores, and each process in the cluster starts twice as slowly - about 10ms on average.

Now, run the benchmark again:

wrk -H 'Connection: keep-alive' --latency -d 5 -c 256 --timeout 8 -t 4 http://localhost:3000/plaintext
Enter fullscreen mode Exit fullscreen mode

This time, the results are as follows:

Running 5s test @ http://localhost:3000/plaintext
  4 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     9.03ms   18.69ms 345.62ms   97.60%
    Req/Sec     9.26k     1.55k   12.23k    83.50%
  Latency Distribution
     50%    6.42ms
     75%    8.32ms
     90%   10.85ms
     99%   85.68ms
  184883 requests in 5.03s, 33.85MB read
Requests/sec:  36720.73
Transfer/sec:      6.72MB
Enter fullscreen mode Exit fullscreen mode

So, 36 thousand requests per second, which is slightly more than twice as fast compared to running on a single core without cluster mode.

Bun on single process

Now let's run the same benchmarks with Bun. Go to the first terminal, press Ctrl+C, and run:

bun bun.mjs
Enter fullscreen mode Exit fullscreen mode

The process starts in about 4ms (almost as fast as in Node.js). When running the same benchmark with wrk, the following result is obtained:

Running 5s test @ http://localhost:3000/plaintext
  4 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.42ms  769.54us  26.37ms   93.00%
    Req/Sec    11.87k     0.86k   12.95k    75.00%
  Latency Distribution
     50%    5.28ms
     75%    5.80ms
     90%    6.04ms
     99%    6.77ms
  236197 requests in 5.04s, 31.99MB read
Requests/sec:  46849.13
Transfer/sec:      6.34MB
Enter fullscreen mode Exit fullscreen mode

So, Bun handles 46 thousand requests per second on a single core, which is 2.5 times faster compared to Node.js.

Bun with cluster mode

Again, go to the first terminal, press Ctrl+C, and run:

bun bun-cluster.mjs
Enter fullscreen mode Exit fullscreen mode

We see that in cluster mode, Bun's processes start just as quickly as without cluster mode.

Now, run the benchmark with wrk again, and the following result is obtained:

Running 5s test @ http://localhost:3000/plaintext
  4 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.09ms    2.08ms  32.22ms   70.02%
    Req/Sec    19.97k     1.99k   27.94k    85.50%
  Latency Distribution
     50%    2.86ms
     75%    4.16ms
     90%    5.70ms
     99%    9.41ms
  399353 requests in 5.07s, 54.08MB read
Requests/sec:  78753.89
Transfer/sec:     10.66MB
Enter fullscreen mode Exit fullscreen mode

So, 78 thousand requests per second. There is a performance increase, but only about 1.5 times compared to non-cluster mode. However, this is twice as fast as Node.js in cluster mode.

Describing a summary from my benchmarking experience, I can say that these are the best results comparing "Bun vs Node.js". It seems that Bun's web server is twice (or sometimes four times) faster, but this speed does not extend to all code. As you gradually increase the amount of JavaScript code in your application, Bun's performance will quickly degrade.

And when Bun works with database code, it shows noticeably worse results compared to Node.js. As far as I understand, this happens due to the significant amount of JavaScript code in database drivers.

How Bun Works with ExpressJS

Run it with the following command:

bun express.mjs
Enter fullscreen mode Exit fullscreen mode

On my machine, Bun launches this code in about 10ms, while Node.js launches it in 4ms, meaning Node.js has a 2.5 times faster cold start.

However, Bun has a special feature designed to minimize startup time. To use it, create an executable file using the following command:

bun build ./express.mjs --compile --minify --outfile mycli
Enter fullscreen mode Exit fullscreen mode

It will generate a mycli file from express.mjs, which can be run as follows:

./mycli
Enter fullscreen mode Exit fullscreen mode

On my machine, this file launches slightly slower (about one millisecond slower) than the uncompiled file. However, this feature is primarily intended for large projects, so no optimization for cold start is noticeable in minimal code. However, the speed of the compiled file is slightly higher.

How Bun Works with Ditsmod

If you clone the seeds from Ditsmod and install the dependencies:

git clone --depth 1 https://github.com/ditsmod/seed.git my-app
cd my-app
bun install
Enter fullscreen mode Exit fullscreen mode

And try to immediately run the application using Bun:

bun run build
bun dist/main.js
Enter fullscreen mode Exit fullscreen mode

It will throw the following error:

1 | (function (entry, fetcher)
    ^
SyntaxError: export 'ValueProvider' not found in './types-and-models.js'
Enter fullscreen mode Exit fullscreen mode

This bug is easily fixed - just delete all tsconfig files from node_modules/@ditsmod:

rm node_modules/@ditsmod/*/tsconfig.json
Enter fullscreen mode Exit fullscreen mode

That's it, now Bun works as expected:

bun dist/main.js
Enter fullscreen mode Exit fullscreen mode

Summary

Personally, I don't yet see any significant advantages for switching to Bun. It has fast dependency installation, a fast web server, and possibly fast SQLite. If you open its repository, you can see that the number of bugs is overwhelming, so the Bun team has a hard time handling them.

If nothing significant happens in Bun's development over the next year, it will be unpromising for me.

Top comments (0)