---
title: Bun v1.1.31
description: "Fixes 41 bugs (addressing 595 👍). node:http2 server and gRPC server support, ca and cafile support in bun install, Bun.inspect.table, bun build --drop, iterable SQLite queries, iterator helpers, Promise.try, Buffer.copyBytesFrom, and several Node.js compatibility improvements and bugfixes."
date: "2024-10-18T03:55:06.849Z"
author: ashcon
---

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

This release fixes 41 bugs (addressing 595 👍). It includes node:http2 server and gRPC server support, ca and cafile support in bun install, Bun.inspect.table, bun build --drop, Promise.try, Buffer.copyBytesFrom, iterable SQLite queries, iterator helpers, and several Node.js compatibility improvements and bugfixes.

#### 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
```

## Support for `node:http2` server and gRPC

In this release of Bun, we added support for our [most upvoted](https://github.com/oven-sh/bun/issues/8823) feature request: HTTP2 server and gRPC support. Bun has supported the node:http2 client since [v1.0.13](/blog/bun-v1.0.13#http2-client-support), but we didn't support the server, until now.

In Bun, `node:http2` runs 2.4x faster than in Node v23.

{% raw %}

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">In the next version of Bun<br><br>`node:http2` server support is implemented. For the same code:<br><br>Bun v1.1.31: 128,879 req/s (2.4x faster)<br>Node v23.0.0: 52,785 req/s <a href="https://t.co/SIM0I0Td4T">pic.twitter.com/SIM0I0Td4T</a></p>&mdash; Bun (@bunjavascript) <a href="https://twitter.com/bunjavascript/status/1847014951661326396?ref_src=twsrc%5Etfw">October 17, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

{% /raw %}

You can use the [`node:http2`](https://nodejs.org/api/http2.html#core-api) API to create an HTTP2 server.

```js
import { createSecureServer } from "node:http2";
import { readFileSync } from "node:fs";

const server = createSecureServer({
  key: readFileSync("privkey.pem"),
  cert: readFileSync("cert.pem"),
});

server.on("error", (error) => console.error(error));
server.on("stream", (stream, headers) => {
  stream.respond({
    ":status": 200,
    "content-type": "text/html; charset=utf-8",
  });
  stream.end("<h1>Hello from Bun!</h1>");
});

server.listen(3000);
```

With HTTP2 support, you can also use gRPC with packages like [`@grpc/grpc-js`](https://www.npmjs.com/package/@grpc/grpc-js).

```js
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const packageDefinition = protoLoader.loadSync("benchmark.proto", {});
const proto = grpc.loadPackageDefinition(packageDefinition).benchmark;
const fs = require("fs");

function ping(call, callback) {
  callback(null, { message: "Hello, World" });
}

function main() {
  const server = new grpc.Server();
  server.addService(proto.BenchmarkService.service, { ping: ping });
  const tls =
    !!process.env.TLS &&
    (process.env.TLS === "1" || process.env.TLS === "true");
  const port = process.env.PORT || 50051;
  const host = process.env.HOST || "localhost";
  let credentials;
  if (tls) {
    const ca = fs.readFileSync("./cert.pem");
    const key = fs.readFileSync("./key.pem");
    const cert = fs.readFileSync("./cert.pem");
    credentials = grpc.ServerCredentials.createSsl(ca, [
      { private_key: key, cert_chain: cert },
    ]);
  } else {
    credentials = grpc.ServerCredentials.createInsecure();
  }
  server.bindAsync(`${host}:${port}`, credentials, () => {
    console.log(
      `Server running at ${tls ? "https" : "http"}://${host}:${port}`,
    );
  });
}

main();
```

## CA support in `bun install`

You can now configure CA certificates for `bun install`. This is useful when you need to install packages from your company's private registry, or if you want to use self-signed certificate.

```toml#bunfig.toml
[install]
# The CA certificate as a string
ca = "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"

# A path to a CA certificate file. The file can contain multiple certificates.
cafile = "path/to/cafile"
```

If you don't want to change your `bunfig.toml` file, you can also use the `--ca` and `--cafile` flags.

```sh
$ bun install --cafile=/path/to/cafile
$ bun install --ca="..."
```

If you are using an existing `.npmrc` file, you can also configure CA certificates there.

```sh#.npmrc
cafile=/path/to/cafile
ca="..."
```

## `bun build --drop`

You can use `--drop` to remove function calls from your JavaScript bundle. This is useful if you want to remove debug code from your production bundle. For example, if you pass `--drop=console`, all calls to `console.log` will be removed from your code.

{% codetabs %}

```ts#JavaScript
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
  drop: ["console", "anyIdentifier.or.propertyAccess"],
})
```

```bash#CLI
$ bun build ./index.tsx --outdir ./out --drop=console --drop=anyIdentifier.or.propertyAccess
```

{% /codetabs %}

### `bun --drop`

`--drop` also works at runtime.

```ts#index.ts
for (let i = 0; i < 3; i++) {
  console.log("hello called!");
}
```

Before `--drop`, you'd see `hello called!` 3 times.

```sh
$ bun ./index.ts
hello called!
hello called!
hello called!
```

With `--drop=console`, `console.log` calls get dropped and you don't see `hello called!` anymore.

```sh
$ bun --drop=console ./index.ts
# no output
```

## `Bun.inspect.table()`

You can now use `Bun.inspect.table` to format tabular data into a string. It is similar to [`console.table`](https://developer.mozilla.org/en-US/docs/Web/API/console/table_static), except it returns a string rather than printing to the console.

```ts
console.log(
  Bun.inspect.table([
    { a: 1, b: 2, c: 3 },
    { a: 4, b: 5, c: 6 },
    { a: 7, b: 8, c: 9 },
  ]),
);

// ┌───┬───┬───┬───┐
// │   │ a │ b │ c │
// ├───┼───┼───┼───┤
// │ 0 │ 1 │ 2 │ 3 │
// │ 1 │ 4 │ 5 │ 6 │
// │ 2 │ 7 │ 8 │ 9 │
// └───┴───┴───┴───┘
```

You can also pass an array of property names to display only a subset of properties.

```ts
console.log(
  Bun.inspect.table(
    [
      { a: 1, b: 2, c: 3 },
      { a: 4, b: 5, c: 6 },
    ],
    ["a", "c"],
  ),
);

// ┌───┬───┬───┐
// │   │ a │ c │
// ├───┼───┼───┤
// │ 0 │ 1 │ 3 │
// │ 1 │ 4 │ 6 │
// └───┴───┴───┘
```

If you want to enable ANSI colors, you can set the `colors` property on the options object.

```ts
console.log(
  Bun.inspect.table(
    [
      { a: 1, b: 2, c: 3 },
      { a: 4, b: 5, c: 6 },
    ],
    {
      colors: true,
    },
  ),
);
```

## Iterable SQLite queries

Bun has a built-in [SQLite](/docs/api/sqlite) API, that makes it easy to query SQLite databases. Instead of returning an array of rows, you can now return an iterator that yields rows as they are returned from the database.

```ts
import { Database } from "bun:sqlite";

const sst = new Database(":memory:");
sst.run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)");

class User {
  id: number;
  name: string;
  email: string;

  get nameAndEmail() {
    return `${this.name} <${this.email}>`;
  }
}

const rows = sst
  .query("SELECT * FROM users")
  .as(User)
  .iterate() // <--- here
  // call the .nameAndEmail property on each row
  .map((row) => row.nameAndEmail);

for (const row of rows) {
  console.log(row);
}

// prints nothing because sst has no users
```

You can also call the `.iterate()` method on a query to get an iterator that yields rows as they are returned from the database.

```ts
for (const row of db.query("SELECT * FROM users").iterate()) {
  console.log(row); // { id: 1, name: "Bun" }
}
```

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

## Iterator helpers

In this release of Bun, there are new APIs that make it easier to work with JavaScript iterators and generators. These APIs were introduced in a [TC39 proposal](https://github.com/tc39/proposal-iterator-helpers), and are now available in Safari and Chrome. Thanks to the WebKit team for implementing these APIs, especially [@sosukesuzuki](https://github.com/sosukesuzuki) and [@shvaikalesh](https://github.com/shvaikalesh)!

### `iterator.map(fn)`

Returns an iterator that yields the results of the `fn` function applied to each value of the original iterator, similar to `Array.prototype.map`.

```ts
function* range(start: number, end: number): Generator<number> {
  for (let i = start; i < end; i++) {
    yield i;
  }
}

const result = range(3, 5).map((x) => x * 2);
result.next(); // { value: 6, done: false }
```

### `iterator.flatMap(fn)`

Returns an iterator that yields the values of the original iterator, but flattens the results of the `fn` function, similar to `Array.prototype.flatMap`.

```ts
function* randomThoughts(): Generator<string> {
  yield "Bun is written in Zig";
  yield "Bun runs JavaScript and TypeScript";
}

const result = randomThoughts().flatMap((x) => x.split(" "));
result.next(); // { value: "Bun", done: false }
result.next(); // { value: "is", done: false }
// ...
result.next(); // { value: "TypeScript", done: false }
```

### `iterator.filter(fn)`

Returns an iterator that only yields values that pass the `fn` predicate, similar to `Array.prototype.filter`.

```ts
function* range(start: number, end: number): Generator<number> {
  for (let i = start; i < end; i++) {
    yield i;
  }
}

const result = range(3, 5).filter((x) => x % 2 === 0);
result.next(); // { value: 4, done: false }
```

### `iterator.take(n)`

Returns an iterator that yields the first `n` values of the original iterator.

```ts
function* odds(): Generator<number> {
  let i = 1;
  while (true) {
    yield i;
    i += 2;
  }
}

const result = odds().take(1);
result.next(); // { value: 1, done: false }
result.next(); // { done: true }
```

### `iterator.drop(n)`

Returns an iterator that yields all values of the original iterator, except the first `n` values.

```ts
function* evens(): Generator<number> {
  let i = 0;
  while (true) {
    yield i;
    i += 2;
  }
}

const result = evens().drop(2);
result.next(); // { value: 4, done: false }
result.next(); // { value: 6, done: false }
```

### `iterator.reduce(fn, initialValue)`

Reduces the values of an iterator with a function, similar to `Array.prototype.reduce`.

```ts
function* powersOfTwo(): Generator<number> {
  let i = 1;
  while (true) {
    yield i;
    i *= 2;
  }
}

const result = powersOfTwo()
  .take(5)
  .reduce((acc, x) => acc + x, 0);
console.log(result); // 15
```

### `iterator.toArray()`

Returns an array that contains all the values of the original iterator. Make sure that the iterator is finite, otherwise this will cause an infinite loop.

```ts
function* range(start: number, end: number): Generator<number> {
  for (let i = start; i < end; i++) {
    yield i;
  }
}

const result = range(1, 5).toArray();
console.log(result); // [1, 2, 3, 4]
```

### `iterator.forEach(fn)`

Calls the `fn` function on each value of the original iterator, similar to `Array.prototype.forEach`.

```ts
function* randomThoughts(): Generator<string> {
  yield "Bun is written in Zig";
  yield "Bun runs JavaScript and TypeScript";
}

const result = randomThoughts().forEach((x) => console.log(x));
// Bun is written in Zig
// Bun runs JavaScript and TypeScript
```

### `iterator.find(fn)`

Returns the first value of the original iterator that passes the `fn` predicate, similar to `Array.prototype.find`. If no such value exists, it returns `undefined`.

```ts
function* range(start: number, end: number): Generator<number> {
  for (let i = start; i < end; i++) {
    yield i;
  }
}

const result = range(0, 99).find((x) => x % 100 === 0);
console.log(result); // undefined
```

## Promise.try

The `Promise.try` method is similar to `Promise.resolve`, but it also works with synchronous functions.

```ts
Promise.try(() => {
  return 1 + 1;
}).then((result) => {
  console.log(result); // 2
});
```

This is a stage4 TC39 proposal (i.e. it has graduated from proposal to standardized ECMAScript). Thanks to [@rkirsling](https://github.com/rkirsling) for implementing this!

## 9x faster `Error.captureStackTrace`

{% raw %}

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">In the next version of Bun<br><br>Error.captureStackTrace(err) gets 9x faster <a href="https://t.co/Ej7XW8KPNk">pic.twitter.com/Ej7XW8KPNk</a></p>&mdash; Jarred Sumner (@jarredsumner) <a href="https://twitter.com/jarredsumner/status/1845736532298383391?ref_src=twsrc%5Etfw">October 14, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
{% /raw %}

## `expect(fn).toThrow()` prints the return value if it does not throw

Before:

![image](https://github.com/user-attachments/assets/7a380fc4-71ef-4c34-b91d-d5aa724cba20)

And now:

![image](https://github.com/user-attachments/assets/dca4f20d-175f-4a4e-9f05-9787b536f371)

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

## Warn on first idle request timeout

{% raw %}

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">In the next version of Bun<br><br>Added a warning when a request times out automatically in Bun.serve() without explicitly passing `idleTimeout` and without using AbortSignal <a href="https://t.co/krMmUNi14x">pic.twitter.com/krMmUNi14x</a></p>&mdash; Jarred Sumner (@jarredsumner) <a href="https://twitter.com/jarredsumner/status/1844560929897529417?ref_src=twsrc%5Etfw">October 11, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

{% /raw %}

## New error: Mismatched JSX closing tag

Previously, the following code would not throw an error, even though it's invalid JSX:

```tsx
const Oopsie = () => {
  return (
    <h1>
      That should be an h1! Not a div.
    </div>
  );
};
```

We should have always thrown an error here, but we were not. Now we do:

```jsx
❯ bun build Oopsie.tsx
5 |     </div>
          ^
error: Expected closing JSX tag to match opening tag "<h1>"
    at Oopsie.tsx:5:7

3 |     <h1>
         ^
note: Opening tag here:
   at Oopsie.tsx:3:6
```

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

## Node.js compatibility

### New: `Buffer.copyBytesFrom(view[, offset[, length]])`

You can now use the `Buffer.copyBytesFrom` method to create a new `Buffer` by copying bytes from a typed array or DataView.

```js
const u16 = new Uint16Array([0, 0xffff]);
const buf = Buffer.copyBytesFrom(u16, 1, 1);
u16[1] = 0;
console.log(buf.length); // 2
console.log(buf[0]); // 255
console.log(buf[1]); // 255
```

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

### Fixed: `fs.open()`

We fixed various issues in `fs.open()`, so it more closely matches Node.js's behavior. Thanks to [@nektro](https://github.com/nektro) for fixing this!

### Fixed: Node-API bugs

We've been working on fixing bugs in Bun's implementation of Node-API. Thanks to [@190n](https://github.com/190n) for fixing these bugs!

- `napi_create_empty_array` does not crash when the array is too large
- `napi_create_empty_array` uses empty slots, instead of `undefined` values
- `napi_get_value_int32` uses the same bitwise conversions as in JavaScript
- `napi_get_value_int64` now matches Node.js's behavior
- `napi_throw_error` and `napi_create_error` are now tested and don't sometimes crash

### Fixed: Setting `UV_THREADPOOL_SIZE`

There are some Node.js packages that set the `UV_THREADPOOL_SIZE` environment variable to control the number of threads used by libuv. While Bun only uses libuv on Windows, and only for some APIs, it will now respect this environment variable.

### Fixed: `Buffer.from` JSON serialization

When you call `JSON.stringify` on a Buffer, it adds `{type: "Buffer", value: [...buffer contents]}` to the JSON. This already worked, but Buffer.from would not accept this JSON. Now it does.

```js
const buf = Buffer.from([1, 2, 3]);
JSON.stringify(buf); // "{"type":"Buffer","data":[1,2,3]}"
Buffer.from(JSON.parse('{"type":"Buffer","data":[1,2,3]}'))[0] === 1; // works
```

Previously, this would throw:

```js
TypeError: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object.
      at [file]:3:20
```

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

### Fixed: `node:child_process.SpawnResult` `.stderr` should be null if `.stdio` is not `"pipe"`

```ts
import child_process from "node:child_process";

const res = child_process.spawn("ls", {
  stdio: "inherit",
});
console.log(res.stderr); // now 'null'
```

This unblocked use of the [`tinyexec`](https://www.npmjs.com/package/tinyexec) package.

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

## Bugs squashed

### Fixed: Format of `console.table` with numeric keys

We fixed a bug where `console.table` would format with incorrect spacing when the keys were numeric. Thanks to [@pfgithub](https://github.com/pfgithub) for fixing this!

```js
console.table({test: {"10": 123, "100": 154}});

// Before
┌──────┬─────┬─────┐
│      │ 10  │ 100 │
├──────┼─────┼─────┤
│ test │     │     │
└──────┴─────┴─────┘

// After
┌─────────┬─────┬─────┐
│ (index) │ 10  │ 100 │
├─────────┼─────┼─────┤
│ test    │ 123 │ 154 │
└─────────┴─────┴─────┘
```

### Fixed: Crash using `Bun.color`

In a recent release, we introduced [`Bun.color`](/docs/api/color), an API that allows you to parse and transform colors in different formats, including css, ansi, hex, rgb, hsl, and more.

We fixed a bug where `Bun.color` would crash if you did not pass it a format string.

### Fixed: Regression with `instanceof`

An `instanceof` regression introduced in Bun v1.1.30 through a WebKit upgrade has been fixed. The bug could be caused by JavaScript code storing the output value of `instanceof` in the same variable as the input. The error message would look like:

```sh
error: [BUG] Unreachable
      at ... (input.js:2247:47)
```

This bug was most often seen when using [`sass`](https://www.npmjs.com/package/sass) with source maps enabled.

Fixed thanks to [@hyjorc1](https://github.com/hyjorc1)!

### Fixed: Transpiler bug with `using` and generators

We fixed a bug where a variable declaration before a `using` statement would cause the transpiler to hoist a generator outside the scope of the `using` declaration. This would cause a `ReferenceError`, but has now been fixed thanks to [@snoglobe](https://github.com/snoglobe).

### Fixed: File permissions with `bun install`

Some npm packages are published with incorrect file permissions, we added a check in Bun to ensure that files extracted from an npm package are at-least readable. This matches the behavior of `npm install`.

### Fixed: Missing metadata publishing with `bun publish`

A bug was fixed where `bun publish` was sending publish requests without important package metadata, including dependencies and binaries from `bin` or `directories.bin`. This would cause published packages to install incorrectly due to missing transitive dependencies and binaries in `node_modules/.bin`.

### Fixed: empty string argument for `fs.mkdir`

An integer overflow caused by passing an empty string to `fs.mkdir` has been fixed. This would only happen when the `recursive` option was set to `true`.

```js
const fs = require("fs");
fs.mkdirSync("", { recursive: true }); // throws ENOENT
```

### Fixed: fetch `keepalive` option

The `keepalive` option for `fetch` was previously ignored. Now it disables the "Connection: keep-alive" header from being sent by default.

```js
const res = await fetch("https://example.com", { keepalive: false });
console.log(res.headers.get("connection")); // "close"
```

## Thanks to 19 contributors!

- [@190n](https://github.com/190n)
- [@cirospaciari](https://github.com/cirospaciari)
- [@deiga](https://github.com/deiga)
- [@DonIsaac](https://github.com/DonIsaac)
- [@dylan-conway](https://github.com/dylan-conway)
- [@Electroid](https://github.com/Electroid)
- [@FaSe22](https://github.com/FaSe22)
- [@fel1x-developer](https://github.com/fel1x-developer)
- [@huseeiin](https://github.com/huseeiin)
- [@Jarred-Sumner](https://github.com/Jarred-Sumner)
- [@nektro](https://github.com/nektro)
- [@paperclover](https://github.com/paperclover)
- [@pfgithub](https://github.com/pfgithub)
- [@refi64](https://github.com/refi64)
- [@RiskyMH](https://github.com/RiskyMH)
- [@Skywalker13](https://github.com/Skywalker13)
- [@snoglobe](https://github.com/snoglobe)
- [@SunsetTechuila](https://github.com/SunsetTechuila)
- [@zackradisic](https://github.com/zackradisic)
