Note
We're hiring C/C++ and Zig engineers to build the future of JavaScript!
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 upgradeWorkspaces 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"]
}Note
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 packagebdepends ona,bun installwill symlink your localpackages/adirectory into thenode_modulesfolder ofb, instead of trying to download it from the npm registry. - Dependencies can be de-duplicated. If
aandbshare a common dependency, it will be hoisted to the rootnode_modulesdirectory. 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.tsHow fast is Bun from 1 to 10?11Good answer!Custom headers in WebSocket#
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.
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:
✓ outer > my testAfter:
✓ outer > inner > my testTest 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.
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.
- Bun no longer checks the
browserproperty inpackage.json. This is because some packages would disable Node.js functionality, which is not what we want for Bun. - For better Node.js & npm compatibility, Bun's JavaScript runtime now reads the
"node"export condition in package.jsonexports.
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 <package> 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#
6260aaa | Implements crypto.scrypt() and more node:crypto APIs |
d726a17 | Implements Bun.RIPEMD160 |
940ecd0 | Implements process.uptime() and process.umask() |
85eda20 | Implements Bun.CryptoHasher |
#1727 | Implements expect().toThrow() |
#1659 | Implements Buffer.{swap16,swap32,swap64} — @malcolmstill |
c18165b | Adds support for ttl: true in Bun.listen() |
734b5b8 | Adds a closeActiveConnections parameter to Server.stop() and Socket.stop() |
8e9af05d | Changes WebSocket to accept URLs with http or https protocol |
Additional fixes#
#1670 | Fix incorrect 206 Partial Content response |
#1674 | Fixes a bug where console.log({ name: "" }) would print incorrect formatting |
3d60b87 | Fixes ReadableStream.pipeTo() |
#1689 | Fixes bun wiptest not waiting for async lifecycle hooks |
#1700 | Fixes lingering processes with Bun.listen() and Bun.connect() |
#1705 #1730 | Fixes the connectError callback not being invoked with Bun.listen() |
#1695 | Fixes a transpiler bug that affected @tensorflow/tfjs-backend-wasm — @theoparis |
#1716 | Fixes TextDecoder being exported as TextEncoder (oops!) — @torbjorn-kvist |
#1734 | Fixes unhandled Promise rejections not causing an error exit code |
fadd1c0 | Fixes when Bun.connect() would not reject on connection error |
2392e48 | Fixes when an uncaught error in a describe block would exit bun wiptest |
88ffdc5 | Fixes a transpiler bug with export default class implements |
#1800 | Fixes Response not accepting a status under 2xx |
7dd28bb | Fixes an issue where Bun.which() would inadvertently detect a directory on macOS |
— | Fix various bugs and improved compatibility with Node-API: 59655d0 f79301c 994e58b c505f17 02f0212 d54e23c 59655d0 f79301c |
Contributors#
Thank you to everyone who contributed to Bun v0.5!
- @Vexu for helping upgrade Bun to the latest version of Zig
- @alexlamsl for
npmworkspaces,net.Socket, improvements tobun install, and many many fixed bugs - @ThatOneBro for
node:readline - @colinhacks for introducing canary builds at
bun-types@canary - @cirospaciari for implementing
HTTP_PROXYsupport - @srh, @lucifer1004, @u9g, @eltociear, @jiaz, @malcolmstill, and @ethanburrell for contributing to Bun


