Bun v0.5 is packed with new features including npm workspaces, Bun.dns, and support for node:readline. There’s improved compatibility with node:tls and node:net so several database drivers now work in Bun for the first time, including Postgres.js, mysql2, node-redis, and others. Bun also continues to get faster and more stable — Buffer instantiation is 10x faster, crypto.createHasher() is 50x faster, and bun install got dozens of bugfixes.

# Install Bun
curl https://bun.sh/install | bash

# Upgrade to latest release of Bun
bun upgrade

Workspaces in package.json

Bun now supports workspaces in package.json, and it’s fast. Bun installs the Remix monorepo in about 500ms on Linux.

  • 28x faster than npm install
  • 12x faster than yarn install (v1)
  • 8x faster than pnpm install

What are workspaces?

Workspaces make it easy to develop complex software as a monorepo consisting of several independent packages. To try it, specify a list of sub-packages in the workspaces field of your package.json; it’s conventional to place these sub-packages in a directory called packages.

{
  "name": "my-project",
  "version": "1.0.0",
  "workspaces": ["packages/a", "packages/b"]
}

Bun doesn’t support globs for workspace names yet, but this is coming soon!

This has a couple major benefits.

  • Code can be split into logical parts. If one package relies on another, you can simply add it as a dependency with bun add. If package b depends on a, bun install will symlink your local packages/a directory into the node_modules folder of b, instead of trying to download it from the npm registry.
  • Dependencies can be de-duplicated. If a and b share a common dependency, it will be hoisted to the root node_modules directory. This reduces redundant disk usage and minimizes “dependency hell” issues associated with having multiple versions of a package installed simultaneously.

Bun.dns and node:dns

Bun can now resolve domain names using the built-in Bun.dns API. At the moment, Bun.dns exposes a single function: lookup.

import { dns } from "bun";

const records = await dns.lookup("example.com", { family: 4 });
console.log(records); // [{ address: "93.184.216.34" }]

We’ve also added a minimal implementation of Node.js’ node:dns that uses Bun.dns under the hood. It’s powered by c-ares and non-blocking getaddrinfo on MacOS.

import { resolve4 } from "node:dns/promises";

const records = await resolve4("example.com");
console.log(records); // [ "93.184.216.34" ]

Sockets using node:tls and node:net

Bun now supports the creation of sockets using net.connect() and tls.connect(). This unblocks several database driver libraries. A handful of representative examples:

Connect to Postgres in Bun using Postgres.js by @porsager:

import postgres from "postgres";

const sql = postgres();
const [{ version }] = await sql`SELECT version()`;

console.log(version); // "PostgreSQL 14.2 ..."

Connect to MySQL in Bun using mysql2 client by @sidorares:

import { createConnection } from "mysql2/promise";

const connection = await createConnection({
  host: "localhost",
  user: "root",
  database: "test",
});

const [rows] = await connection.execute("SELECT 1+2 AS count");
console.log(rows); // [{ count: 3 }]

Connect to Redis from Bun using the official Node.js client:

import { createClient } from "redis";

const client = createClient();
await client.connect();

await client.set("key", "Hello!");
const value = await client.get("key");

console.log(value); // "Hello!"

Support for node:readline

Bulding CLI tools should be much easier now that Bun supports the node:readline module.

import * as readline from "node:readline/promises";

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: true,
});

const answer = await rl.question("How fast is Bun from 1 to 10?n");
if (parseInt(answer) > 10) {
  console.log("Good answer!");
}

Running this script yields:

$ bun readline.ts
How fast is Bun from 1 to 10?
> 11
Good answer!

A long-standing feature request on the WebSocket spec is the ability to set custom headers when opening a WebSocket. While this hasn’t yet landed in the WebSocket standard, Bun now implements it. This allows users to customize the headers used for the WebSocket client handshake request.

const ws = new WebSocket("ws://localhost/chat", {
  headers: {
    Authorization: "...",
  },
});

Improvements to bun wiptest

While bun wiptest is still a work in progress, we continue to increase Bun’s compatibility with Jest.

test.skip()

You can use test.skip() to skip unwanted tests.

import { describe, test, expect } from "bun:test";

describe("fetch()", () => {
  test.skip("can connect to localhost", async () => {
    const response = await fetch("http://localhost");
    expect(response.ok).toBe(true);
  });

  test("can connect to example.com", async () => {
    const response = await fetch("http://example.com");
    expect(response.ok).toBe(true);
  });
});

When you skip a test, it will appear as grayed out in the test output.

bun wiptest output

expect(fn).toThrow()

You can use expect(fn).toThrow() to catch expected errors.

import { test, expect } from "bun:test";

test("catch error", async () => {
  expect(() => {
    throw new Error();
  }).toThrow();
});

describe labels are included in the output

Previously, nested describe labels were not included in the test runner output. Thanks to @ethanburrell, this has been fixed.

Before:

After:

✓ outer > inner > my test

Test file:

import { describe, test } from "bun:test";

describe("outer", () => {
  describe("inner", () => {
    test("my test", () => {});
  });
});

Performance boosts

10x faster new Buffer()

Previously, the Buffer implementation in Bun was using Object.setPrototypeOf() to create each new instance. Eliminating this bottleneck makes it 10x faster to instantiate a small Buffer in Bun.

10x faster Buffer

50x faster crypto.createHash()

Previously, Bun was using a pure JavaScript implementation of crypto.createHash(). Now it’s implemented using native code from BoringSSL, yielding a 50x speed improvement.

Support for HTTPS_PROXY

Bun will now recognize the HTTPS_PROXY, HTTP_PROXY, and NO_PROXY enviroment variables when making outgoing HTTP requests, which includes fetch() and bun install. These variables allow you to specify a proxy to forward, or not forward, certain HTTP requests and are useful when running Bun within a corporate firewall.

export HTTPS_PROXY="http://proxy.example.com:8080"
export NO_PROXY="localhost,noproxy.example.com"

If you want to learn more about these variables, GitLab wrote a nice explainer.

Module resolution changes

There are two changes to module resolution that may impact a few packages.

  1. Bun no longer checks the browser property in package.json. This is because some packages would disable Node.js functionality, which is not what we want for Bun.
  2. For better Node.js & npm compatibility, Bun’s JavaScript runtime now reads the "node" export condition in package.json exports.

The order Bun’s JavaScript runtime reads package.json "exports" conditions is:

["bun", "worker", "module", "node", "browser", "default"];

This means that if a package has a "node" export condition, it will be used instead of the "default" or "browser" export condition.

Changelog

While we continue to add new features to Bun, we’re still focused on improving stability and fixing bugs. This release fixes a number of issues

Fixes to bun install

Several bugs with Bun’s package manager are fixed in this release, mostly by @alexlamsl. Thanks Alex!

#1664 Previously, scoped and private packages configured with bun install would have a registry of localhost, which made very little sense. We’ve fixed this and private registries will now default to the default registry if not specified, which is usually registry.npmjs.org
#1667 Typically, npm clients are supposed to pass the npm-auth-type header, but bun install wasn’t. We’ve fixed this and now bun install will pass the npm-auth-type header
a345efd In some CI environments, like Vercel, linking node_modules/.bin would fail because the /proc filesystem (used to resolve absolute file paths) wasn’t mounted. We’ve fixed this by falling back to fchdir and getcwd when /proc/fd is not available
385c81d A crash sometimes happened when running bun add if the "dependencies" list went from empty to not empty in a package.json
#1665 Use npm as default registry when scopes are configured
#1671 Fix logging verbosity in bun install
#1799 Fix lifecycle script execution in bun install

New APIs

Additional fixes

Contributors

Thank you to everyone who contributed to Bun v0.5!

Read More