Who hashes the fastest: Bun, Node.js, or Deno?

Mayank Choubey
Tech Tonic
Published in
4 min readOct 8, 2022

--

Hashing is the process of converting a given key into another value. A hash function is used to generate the new value according to a mathematical algorithm. The result of a hash function is known as a hash value or, simply, a hash. In this article, I’m going to find out who hashes the fastest using SHA-256 algorithm, which is the most popular one these days. I’m going to compare the hashing speed between:

  • Bun
  • Node.js
  • Deno

The versions

I’ve picked the latest versions for all the three (at the time of writing, which is Oct 8th 22):

The code

Deno provides hashing service through web standard crypto.subtle.digest API. Node had its own crypto implementation for hashing, and now it also provides the same web API like Deno. Bun, as of v0.1.13, provides hashing through node’s old style crypto implementation. Bun doesn’t support the web API implementation.

In all cases, I’m also converting the binary hash to hex string, which is how the hash is used in most of the cases.

Bun

const crypto = require("crypto");const hexStr = crypto.createHash("sha256").update("Hello world!!!").digest("hex");

Node

Old style

import crypto from "node:crypto";const hexStr = crypto.createHash("sha256").update("Hello world!!!").digest("hex");

Web API style

import { webcrypto } from "node:crypto";const msgUint8 = new TextEncoder().encode("Hello world!!!");
const hashBuffer = await webcrypto.subtle.digest("SHA-256", msgUint8);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hexStr = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");

Deno

const msgUint8 = new TextEncoder().encode("Hello world!!!");
const hashBuffer = await crypto.subtle.digest("SHA-256", msgUint8);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hexStr = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");

The environment

The performance test is carried out on:

The results

The test notes down the time taken to generate 5 million SHA-256 hex strings.

As Node has two styles, I need to run the tests two times.

First, let’s see the results with Node’s old style of crypto implementation:

This is a total surprise. Node.js is way, way ahead of the other two. Node can run, 1225K ops / second, compared to Deno’s 75K and Bun’s 150K. That’s a huge difference! Deno and Bun look very slow when compared to Node.js.

Why is this big difference? How come Node is blazing fast?

The only reason I can think of sync vs async ops. Node’s old style crypto implementation is a synchronous op. The sync ops have a simpler implementation, but they also block the event loop. Deno’s implementation is asynchronous, which is pretty complex when compared to sync op. But Deno doesn’t block the event loop. This would explain Deno’s slowness. Bun only has the sync version, which also runs very slow.

Now, let’s keep the Bun aside for now. I’ll now use Node’s web crypto implementation against Deno’s and see if the theory holds right. Here are the results:

Okay, Deno’s hashing is still slow compared to Node.js. But the difference is now reasonable. With async ops, Node can do 123K hashes per second, compared to Deno’s 77K hashes per second. The theory seems right.

Conclusion

Node’s sync hash implementation (using old crypto) is blazing fast compared to others. The blazing fast speed comes at the cost of blocking the event loop.

Node’s async hash implementation speed (using web crypto) is still about double compared to Deno.

Bun only supports sync hashing, and that is very slow (something to improve upon).

--

--