Bun.js Handles 1.29 Million Requests per Second – What’s New in v1.1.25?

Bun v1.1.25 boasts a benchmark of 1.29 million HTTP requests per second and adds node:cluster support, V8 C++ API bindings, a five‑fold S3 upload boost, standalone worker executables, Windows OMGJIT for WebAssembly, plus numerous Node.js compatibility fixes, all illustrated with code examples.

Full-Stack Cultivation Path
Full-Stack Cultivation Path
Full-Stack Cultivation Path
Bun.js Handles 1.29 Million Requests per Second – What’s New in v1.1.25?

Recent release Bun v1.1.25 announced a benchmark of 1.29 million HTTP requests per second, prompting a look at the new improvements.

node:cluster support

Bun now implements the node:cluster API, allowing a set of Bun workers to share a single port for higher throughput on multi‑CPU machines. The typical workflow creates one worker per CPU core, each listening with reusePort, and the OS balances incoming HTTP requests among them.

import cluster from "node:cluster";
import http from "node:http";
import { cpus } from "node:os";
import process from "node:process";

if (cluster.isPrimary) {
  console.log(`Primary process ${process.pid} running`);
  for (let i = 0; i < cpus().length; i++) {
    cluster.fork();
  }
  cluster.on("exit", (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} exited`);
  });
} else {
  // Requests are handled by workers, not the primary
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end("hello world
");
  }).listen(3000);
  console.log(`Worker ${process.pid} started`);
}
Note: reusePort works only on Linux; Windows and macOS cannot perform the expected load‑balancing.

Support for V8 public C++ API

Bun now exposes V8’s public C++ API, enabling packages such as cpu‑features to run. Unlike Node.js, which is built on V8, Bun is built on JavaScriptCore, so a custom C++ translation layer is required to bridge V8 APIs to JavaScriptCore.

#include "v8.h"
#include "V8Primitive.h"
#include "V8MaybeLocal.h"
#include "V8Isolate.h"

namespace v8 {
  enum class NewStringType { /* ... */ };
  class String : Primitive {
  public:
    enum WriteOptions { /* ... */ };
    BUN_EXPORT static MaybeLocal<String> NewFromUtf8(Isolate* isolate, char const* data, NewStringType type, int length = -1);
    BUN_EXPORT int WriteUtf8(Isolate* isolate, char* buffer, int length = -1, int* nchars_ref = nullptr, int options = NO_OPTIONS) const;
    BUN_EXPORT int Length() const;
    // Convert native string to JSC::JSString*
    JSC::JSString* localToJSString() { return localToObjectPointer<JSC::JSString>(); }
  };
}

This bridging is complex because V8 uses a moving, concurrent garbage collector with explicit handle scopes, whereas JavaScriptCore uses a non‑moving concurrent collector that scans stack memory.

Previously importing a package that relied on these APIs produced errors such as:

console.log(require("cpu-features")());
dyld[94465]: missing symbol called
fish: Job 1, 'bun index.ts' terminated by signal SIGABRT (Abort)

Now cpu‑features imports and runs successfully, showing the architecture and flags:

$ bun index.ts
{
  arch: "aarch64",
  flags: {
    fp: true,
    asimd: true,
    // ...
  },
}

S3 upload speed 5× faster

A bug in Bun’s node:http client was fixed, resulting in a five‑fold increase in upload speed to Amazon S3.

Standalone executable workers

Bun’s single‑file standalone executables now support binding Worker and node:worker_threads. To compile a worker into an executable, use:

bun build --compile ./main.ts ./my-worker.ts

Example code:

// main.ts
console.log("Hello from main thread!");
new Worker("./my-worker.ts");

// my-worker.ts
console.log("Hello from another thread!");

OMGJIT for faster WebAssembly on Windows

On Windows, WebAssembly now leverages JavaScriptCore’s optimizing JIT, called OMGJIT, delivering faster execution.

Node.js compatibility improvements

The execa package now works correctly. A previous bug in EventTarget.setMaxListeners caused "undefined is not a function" errors for packages like execa. The bug has been fixed:

import { execa } from "execa";
const { stdout } = await execa`echo "test"`;

Another fix addresses a bug where calling destroy() on a TCP connection left the event loop active, causing processes (e.g., postgres) to hang indefinitely. The corrected pattern is:

import net from "node:net";
const server = net.createServer((socket) => {
  socket.on("connect", (data) => {
    socket.destroy();
    // event loop still active before fix
  });
});
server.listen(3000);

These fixes ensure proper shutdown of TCP connections and prevent lingering event‑loop activity.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PerformancewasmBunv8javascriptcores3Workersnode:cluster
Full-Stack Cultivation Path
Written by

Full-Stack Cultivation Path

Focused on sharing practical tech content about TypeScript, Vue 3, front-end architecture, and source code analysis.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.