---
title: Bun v1.1.25
description: "Fixes 42 bugs (addressing 470 👍). Support for `node:cluster` and V8's C++ API. Faster WebAssembly on Windows with OMGJIT. 5x faster S3 uploads with @aws-sdk/client-s3, Worker in standalone executables, and more Node.js compatibility improvements and bug fixes."
date: "2024-08-21T05:25:44.606Z"
author: ashcon
---

Bun v1.1.25 is here! This release fixes 42 bugs (addressing 470 👍). Support for `node:cluster` and V8's C++ API. Faster WebAssembly on Windows with OMGJIT. 5x faster S3 uploads with @aws-sdk/client-s3, Worker in standalone executables, and more Node.js compatibility improvements and bug fixes.

{% callout %}
We're hiring [systems engineers](/careers) in San Francisco to build the future of JavaScript!
{% /callout %}

#### To install Bun

{% codetabs %}

```sh#curl
$ curl -fsSL https://bun.sh/install | bash
```

```sh#npm
$ npm install -g bun
```

```sh#powershell
$ powershell -c "irm bun.sh/install.ps1|iex"
```

```sh#scoop
$ scoop install bun
```

```sh#brew
$ brew tap oven-sh/bun
$ brew install bun
```

```sh#docker
$ docker pull oven/bun
$ docker run --rm --init --ulimit memlock=-1:-1 oven/bun
```

{% /codetabs %}

#### To upgrade Bun

```sh
$ bun upgrade
```

## `node:cluster` support

Bun now supports the [`node:cluster`](https://nodejs.org/api/cluster.html) API.

This allows you to run a pool of Bun workers that share the same port, enabling higher throughput and utilization on machines with many CPU cores. This is great for load balancing in production environments.

{% raw %}

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">In the next version of Bun<br><br>Initial node:cluster support has landed. Here&#39;s 1.29 million HTTP requests per second in TypeScript. <a href="https://t.co/YzU1cZxk3S">pic.twitter.com/YzU1cZxk3S</a></p>&mdash; Bun (@bunjavascript) <a href="https://twitter.com/bunjavascript/status/1825075013877457002?ref_src=twsrc%5Etfw">August 18, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
{% /raw %}

Here's an example of how it works:

- The primary worker spawns `n` child workers (usually equal to the number of CPU cores)
- Each child worker listens on the same port (using [`reusePort`](https://lwn.net/Articles/542629/))
- Incoming HTTP requests are load balanced across the child workers

```js
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.pid} is running`);

  // Start N workers for the number of CPUs
  for (let i = 0; i < cpus().length; i++) {
    cluster.fork();
  }

  cluster.on("exit", (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} exited`);
  });
} else {
  // Incoming requests are handled by the pool of workers
  // instead of the primary worker.
  http
    .createServer((req, res) => {
      res.writeHead(200);
      res.end("hello world\n");
    })
    .listen(3000);

  console.log(`Worker ${process.pid} started`);
}
```

This works with the [`node:http`](https://nodejs.org/api/http.html) APIs, as well as the `Bun.serve()` API.

```js
import cluster from "node:cluster";
import { cpus } from "node:os";

if (cluster.isPrimary) {
  for (let i = 0; i < cpus().length; i++) {
    cluster.fork();
  }
} else {
  Bun.serve({
    port: 3000,
    fetch(request) {
      return new Response(`Hello from Worker ${process.pid}`);
    },
  });
}
```

Note that currently, `reusePort` is only effective on Linux. On Windows and macOS, the operating system does not load balance HTTP connections as one would expect.

Thanks to [@nektro](https://github.com/nektro) for implementing this feature!

## Initial V8 C++ API support

Bun now supports V8's public C++ API, which unblocks packages like `cpu-features` to work in Bun.

This is notable change because Bun is not built on top of [V8](https://v8.dev/) like Node.js. Instead, Bun is built on top of [JavaScriptCore](https://docs.webkit.org/Deep%20Dive/JSC/JavaScriptCore.html), the JavaScript engine that powers Safari.

That means we had to implement our own C++ translation layer between V8's APIs and JavaScriptCore.

```c#src/bun.js/bindings/v8/V8String.cpp
#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;

    JSC::JSString* localToJSString()
    {
        return localToObjectPointer<JSC::JSString>();
    }
};
}
```

This is difficult engineering work. JavaScriptCore and V8 represent JavaScript values differently. V8 uses a moving, concurrent garbage collector with explicit handle scopes whereas JavaScriptCore uses a non-moving concurrent garbage collector that scans stack memory (sort of like an implicit handle scope).

Before, if you tried to import a package that used these APIs, you would get an error like this:

```js
console.log(require("cpu-features")());
```

```sh
dyld[94465]: missing symbol called
fish: Job 1, 'bun index.ts' terminated by signal SIGABRT (Abort)
```

Now, packages like `cpu-features` can be imported and just work in Bun.

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

This is just the start of support for V8's internal APIs. If your package runs into an area of the V8 API that we have not yet implemented, you'll receive an error that directs you to upvote an issue on GitHub.

#### Why support V8's internal APIs?

We did not originally intend to support these APIs, but decided to after we found that many [popular](https://github.com/oven-sh/bun/issues/4290) packages depend on these APIs, such as:

- [`cpu-features`](https://www.npmjs.com/package/cpu-features)
- [`node-canvas@v2`](https://www.npmjs.com/package/canvas)
- [`node-sqlite3`](https://www.npmjs.com/package/sqlite3)
- [`libxmljs`](https://www.npmjs.com/package/libxmljs)
- and many packages using [`nan`](https://www.npmjs.com/package/nan)

In this release, only `cpu-features` is supported from the list above, but we're working on improving support so all of these packages and more just work in Bun.

Thanks to [@190n](https://github.com/190n) for implementing this feature!

## 5x faster S3 uploads with @aws-sdk/client-s3

We fixed a bug in our node:http client implementation and that made uploading to S3 5x faster.

{% raw %}

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">In the next version of Bun<br><br>Uploading files via `<a href="https://twitter.com/AWS?ref_src=twsrc%5Etfw">@aws</a>-sdk/client-s3` gets 5x faster <a href="https://t.co/tptxegT7vh">pic.twitter.com/tptxegT7vh</a></p>&mdash; Ciro Spaciari (@cirospaciari) <a href="https://twitter.com/cirospaciari/status/1826086715393716457?ref_src=twsrc%5Etfw">August 21, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

{% /raw %}

## Worker in standalone executables

Bun's single-file standalone executables now support bundling `Worker` and `node:worker_threads`.

{% codetabs %}

```ts#main.ts
console.log("Hello from main thread!");

new Worker("./my-worker.ts");
```

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

{% /codetabs %}

To compile a standalone executable with a worker, pass the entry points to `bun build --compile`:

```sh
$ bun build --compile ./main.ts ./my-worker.ts
```

This will bundle `my-worker.ts` and `main.ts` as separate entry points in the resulting executable.

### Embedding files in standalone executables without importing

You can now embed files in standalone executables without an explicit `import` statement, if you want.

```sh
$ bun build --compile ./main.ts ./public/**/*.png
```

Usually, you'd have to import the file to use it:

```ts
import logo from "./public/icons/logo.png" with {type: "file"};
```

But, sometimes you want to import a large number of files that may need to programmatically be referenced.

#### Bun.embeddedFiles

The new `Bun.embeddedFiles` API lets you see a list of all embedded files in a standalone executable.

```ts
import { embeddedFiles } from "bun";

for (const file of embeddedFiles) {
  console.log(file.name); // "logo.png"
  console.log(file.size); // 1234
  console.log(await file.bytes()); // Uint8Array(1234) [...]
}
```

This combines all non-javascript entry points and assets into a single array of `Blob` objects sorted by name.

#### Relative imports for embedded files in standalone executables

You can now reference runtime-known imports of embedded files using relative paths in standalone executables.

```ts
function getWasmFilePath(file: string) {
  return require.resolve(`./${file}.wasm`);
}

const wasmFile = getWasmFilePath("my-wasm-file");
console.log(wasmFile); // "./my-wasm-file.wasm"
```

Previously, this was only supported with statically-analyzable imports that are knonwn at build time. Now, you can do this with any embedded file.

### Faster WebAssembly on Windows with OMGJIT

WebAssembly on Windows now supports JavaScriptCore's optimized Just-In-Time compiler (JIT) called OMGJIT.

{% raw %}

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">In the next version of Bun<br><br>JavaScriptCore&#39;s optimizing WebAssembly JIT &quot;OMGJIT&quot; is enabled on Windows, making this wasm hashing benchmark 20% faster <a href="https://t.co/8qhKVS4E6z">pic.twitter.com/8qhKVS4E6z</a></p>&mdash; Bun (@bunjavascript) <a href="https://twitter.com/bunjavascript/status/1824750540062068815?ref_src=twsrc%5Etfw">August 17, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

{% /raw %}

Thanks to Ian Grunert for shipping this feature in WebKit!

## Node.js compatiblity improvements

### `execa` now works

We fixed a bug where Bun was not properly supporting `setMaxListeners()` for `EventTarget`. This affected packages like `execa`, which would error out with `undefined is not a function`.

```js
import { execa } from "execa";

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

If you experienced an error that looks like this, it has now been fixed:

```js
91 |    const controller = new AbortController();
92 |    setMaxListeners(Number.POSITIVE_INFINITY, controller.signal);
      ^
TypeError: undefined is not a function
      at node:events:101:30
      at spawnSubprocessAsync (/node_modules/execa/lib/methods/main-async.js:92:2)
      at execaCoreAsync (/node_modules/execa/lib/methods/main-async.js:26:32)
      at index.mjs:3:26
```

### Fixed: Connection hangs with `node:net` after `destroy()`

We fixed a bug where calling `destroy()` on a TCP connection, didn't always properly exit the process, since the event loop was still active. This would sometimes cause packages like `postgres` to hang indefinitely.

```js
import net from "node:net";

const server = net.createServer((socket) => {
  socket.on("connect", (data) => {
    socket.destroy();
    // This would destroy the connection,
    // but the event loop would still be active
  });
});

server.listen(3000);
```

### Fixed: node:net.Socket's ref and unref this

The `ref` and `unref` methods on `node:net.Socket` were not returning the `this` value.

Now, they return `this`.

Thanks to [@nektro](https://github.com/nektro) for fixing this bug!

## Bugfixes

### Fixed: `TextEncoderStream` yielded the wrong type

In Bun v1.1.23, we introduced support the the `TextEncoderStream` API. We fixed a bug where the chunks from the stream were `Buffer` objects instead of `Uint8Array` objects.

```js
const response = await fetch("https://example.com");
const body = response.body.pipeThrough(new TextEncoderStream());

for await (const chunk of body) {
  console.log(chunk);
  // Before: Buffer
  // Now: Uint8Array
}
```

### Fixed: crash with escaped backticks in Bun's shell

We fixed a crash in Bun's shell that would not properly handle escaped backticks.

```js
import { $ } from "bun";

console.log(await $`cd \`find -name dir\``.text());
```

Thanks to [@zackradisic](https://github.com/zackradisic) for fixing this bug!

### Fixed: JIT crash with `TextEncoder`

We fixed a bug where if `TextEncoder` was JIT'd after being run millions of times, it would crash. This was due to a bug in Bun's generated code for enabling the JIT on a function.

### Fixed: Crash in jest.fn and mock()

A crash that could occur when calling functions on a `jest.fn` or `mock()` object with an unexpected `this` value has been fixed.

### Fixed: Crash in IPC

When a child process exited before the parent process received a message, a crash could occur in some cases.

This has been fixed, thanks to [@cirospaciari](https://github.com/cirospaciari).

### Fixed: console.log a File's name

When you use the web `File` constructor to create a Blob, the name of the file was not being included in the output of `console.log`.

Input:

```js
console.log(new File(["hello world"], "hello.txt"));
```

New:

```ts
File (11 bytes) {
  name: "hello.txt",
  lastModified: 1724218333315
}
```

Previously:

```ts
Blob (11 bytes)
```

### Fixed: rare crash in websocket server

A rare crash that could potentially occur when a long amount of time has passed since the server has called a callback and the `ServerWebSocket` object has been garbage collected has been fixed.

## Thank you to 11 contributors!

- [@190n](https://github.com/190n)
- [@cirospaciari](https://github.com/cirospaciari)
- [@dylan-conway](https://github.com/dylan-conway)
- [@Electroid](https://github.com/Electroid)
- [@Jarred-Sumner](https://github.com/Jarred-Sumner)
- [@MARCROCK22](https://github.com/MARCROCK22)
- [@mroyme](https://github.com/mroyme)
- [@nektro](https://github.com/nektro)
- [@oddyamill](https://github.com/oddyamill)
- [@paperclover](https://github.com/paperclover)
- [@vktrl](https://github.com/vktrl)
- [@zackradisic](https://github.com/zackradisic)
