Bun

Bun v1.0.31


Ashcon Partovi ยท March 14, 2024

Bun is an incredibly fast JavaScript runtime, bundler, transpiler, and package manager โ€” all in one.

Bun v1.0.31 fixes 54 bugs (addresses 113 ๐Ÿ‘ reactions), introduces bun --print, <stdin> | bun run -, bun add --trust, fetch() with Unix sockets, fixes macOS binary size regression, fixes high CPU usage bug in spawn() on older linux, adds util.styleText, Node.js compatibiltiy improvements, bun install bugfixes, and bunx bugfixes.

Previous releases

  • v1.0.30 fixes 27 bugs (addressing 103 ๐Ÿ‘ reactions), fixes an 8x perf regression to Bun.serve(), adds a new --conditions flag to bun build and Bun's runtime, adds support for expect.assertions() and expect.hasAssertions() in Bun's test runner, fixes crashes and improves Node.js compatibility.
  • v1.0.29 fixes 8 bugs. Bun.stringWidth(a) is a ~6,756x faster drop-in replacement for the popular 'string-width' package. bunx checks for updates more frequently. Adds expect().toBeOneOf() in bun:test. Memory leak impacting Prisma is fixed. Shell now supports advanced redirects like '2>&1', '&>'. Reliability improvements to bunx, bun install, WebSocket client, and Bun Shell
  • v1.0.28 fixes 6 bugs (addressing 26 ๐Ÿ‘ reactions). Fixes bugs impacting Prisma and Astro, node:events, node:readline, and node:http2. Fixes a bug in Bun Shell involving stdin redirection and fixes bugs in bun:test with test.each and describe.only.

To install Bun:

curl
npm
brew
docker
curl
curl -fsSL https://bun.sh/install | bash
npm
npm install -g bun
brew
brew tap oven-sh/bun
brew install bun
docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun

To upgrade Bun:

bun upgrade

New: bun --print

You can now use bun --print to evaluate the provided code and print the result using console.log. It's the same as node --print, except it supports top-level await, ESM, CommonJS, TypeScript, and JSX.

bun --print 'fetch("https://api.github.com/repos/bigskysoftware/htmx").then(r => r.json())'

Bun will also await dangling promises so you don't need to append await to your code.

bun --print 'fetch("https://api.github.com/repos/bigskysoftware/htmx").then(r => r.json())'

For reference, here is an equivalent output using node --print:

node --print 'await fetch("https://api.github.com/repos/bigskysoftware/htmx").then(r => r.json())'

We implemented this because many npm packages have postinstall scripts that call node --print, and we don't want bun install to have any issues when you don't have Node.js installed.

Thanks to @dylan-conway for implementing this!

New: Run code from stdin

You can now pipe stdin into Bun using bun run -. This is useful for running code from a file or a script.

echo 'console.log("Hello")' | bun run -
cat file.js | bun run -
bun run - < file.js

As usual in Bun, this works with top-level await, ESM, CommonJS, TypeScript, and JSX.

Thanks to @nektro for adding this feature!

New: bun add --trust <package>

We've made improvements to how Bun handles trustedDependencies in your package.json. By default, Bun does not run postinstall scripts for packages that are not trusted. This is a security feature to prevent malicious code from running on your machine.

When you first add a package, Bun will tell you if the package had a postinstall script that did not run.

bun add v1.0.31
Saved lockfile

installed @biomejs/biome@1.6.1 with binaries:
- biome

1 package installed [55.00ms]

Blocked 1 postinstall. Run `bun pm untrusted` for details.

New: bun pm untrusted

If you want to see which scripts were blocked, you can run bun pm untrusted.

bun pm untrusted v1.0.31

./node_modules/@biomejs/biome @1.6.1
ยป [postinstall]: node scripts/postinstall.js

These dependencies had their lifecycle scripts blocked during install.

If you trust them and wish to run their scripts, use `bun pm trust`.

New: bun pm trust

If you trust the package, you can run bun pm trust [package]. If you want to trust every package, you can also run bun pm trust --all.

bun pm trust v1.0.31

./node_modules/@biomejs/biome @1.6.1
โœ“ [postinstall]: node scripts/postinstall.js

1 script ran across 1 package [71.00ms]

The most popular packages are already trusted by default. You can see the list of trusted packages by running bun pm default-trusted.

If you already know you want to trust a dependency, you can add it using bun add --trust [package]. This will add the package and it's transitive dependencies to your trustedDependencies list so you don't need to run bun pm trust for that package.

{
  "dependencies": {
    "@biomejs/biome": "1.6.1"
  },
   "trustedDependencies": [
     "@biomejs/biome"
   ]
}

Thanks to @dylan-conway for improving this feature!

New: Unix sockets in fetch()

Bun now supports sending HTTP requests over a Unix socket.

const response = await fetch("http://localhost/info", {
  // a file path to a Unix socket
  unix: "/var/run/docker.sock",
});

const { ID } = await response.json();
console.log("Docker ID:", ID);

This means you can send fetch() request to services that speak HTTP but communicate using Unix sockets, like the Docker daemon.

This feature works with fetch and with node:http.

Ordinarily, unix sockets have a file path limit of around 108 characters, but on Linux we've added a workaround to support longer paths.

Abstract domain sockets in fetch()

We also added support for a obscure Linux feature called "abstract domain sockets".

Unlike Unix sockets, abstract sockets do not exist on the filesystem and get cleaned up automatically when both ends are closed. They are useful in environments where one process might not share filesystem permissions with the parent.

import { $, serve } from "bun";

const unix = "\0much-abstract-very-domain";
const server = serve({
  unix,

  fetch(req) {
    return new Response("hello from abstract socket!");
  },
});

// abstract domain sockets don't exist in the filesystem
// and they don't run on a port
await $`rm -rf ${unix.slice(1)}`;

// but we can still make requests to them
await $`curl --abstract-unix-socket ${unix.slice(1)} http://anything/hello`;
await fetch(`http://a:1234/b`, { unix });

server.stop();

Abstract sockets works using fetch(), Bun.serve(), and socketPath in node:http.

Fixed: Bun.spawn() 100% CPU usage bug on older Linux kernels

Correctly spawning processes and monitoring when they exit is extremely complicated.

For Linux, Bun has two implementations for monitoring when a spawned process exits:

  1. Using pidfd_open(2) which was fully added to the Linux Kernel in v5.10 (Dec 2020). pidfd is the most efficient way to monitor when a process exits because it can be used with epoll or io_uring, like other file descriptors.
  2. A fallback implementation using SIGCHLD which is supported on all Linux kernels

In psuedocode, the fallback implementation used to look something like this:

// in a dedicated thread:
while (true) {
  for (const pid of pids) {
    if (wait4(pid, WNOHANG, ...) === pid) {
      pids.delete(pid);
      tellBunThatProcessExited(pid);
    }
  }

  sleepUntilNewPidsOrAnyProcessExits(eventfd, signalfd);
}

There was a bug where the equivalent of sleepUntilNewPidsOrAnyProcessExits would immediately resolve when it should've slept, causing Bun to consume 100% CPU on this thread.

There were two causes of this bug:

  • We were not calling read() on the underlying eventfd, leading it to always be ready to read (and thus never sleep)
  • The signal handler for SIGCHLD was not being installed correctly, leading the thread to never receive the signal

The first bug prevented the second bug from being noticed. Since it never slept, it never needed to wake up to handle the signal.

To prevent this from regressing in the future, we added a test that checks CPU usage when spawning sleep infinity and killing the subprocess after 1 second. If the CPU time is greater than 1/2 a second, the test fails.

Fixed: missing resourceUsage stats in Bun.spawn() on older Linux kernels

Bun supports tracking how much memory, CPU time, and more stats a spawned process consumes. In the fallback implementation on older Linux kernels, we were not able to track these stats. Now we can.

const proc = Bun.spawn({
  cmd: ["sleep", "1"],
});

await proc.exited;

console.log(proc.resourceUsage);

// Before: all 0s

Fixed: bun executable size regression on macOS

In Bun v1.0.28 (last month), we added Bun.stringWidth which used more functions from the ICU internationalization library. A mistake in Bun's build process led to statically-linking the entire ICU library into the Bun executable on macOS. This increased the size of Bun's executable by 32.7 MB.

size on macOSBun version
47.8 MBBun v1.0.31
80.4 MBBun v1.0.30
80.4 MBBun v1.0.29
47.7 MBBun v1.0.28

This regression has been fixed, and we will add monitoring to prevent this from happening again.

Node.js compatibility improvements

New: util.styleText()

Node.js recently added the util.styleText() API that allows you to style text using ANSI escape codes. We added this to Bun.

import { styleText } from "node:util";

console.log(styleText("red", "This is a failure!"));
console.log(styleText("yellow", "This is a warning!"));
console.log(styleText("green", "This is a success!"));

The code above will print the following output:

This is a failure!
This is a warning!
This is a success!

Thanks to @paperdave for working on this!

New: socketPath option in node:http

We added support for the socketPath option in node:http. This allows you to send HTTP requests using a Unix socket or an abstract domain socket.

import { request } from "node:http";

request(
  {
    socketPath: "/var/run/docker.sock",
    path: "/info",
  },
  (res) => {
    let data = "";
    res.on("data", (chunk) => (data += chunk));
    res.on("end", () => console.log(JSON.parse(data)));
  },
);

New: domainToASCII and domainToUnicode

We added support for the url.domainToASCII and url.domainToUnicode APIs. These are legacy Node.js APIs that useful for converting domain names to and from their ASCII and Unicode representations.

import { domainToASCII, domainToUnicode } from "node:url";

console.log(domainToASCII("www.๐Ÿ•.com")); // => www.xn--xj8h.com
console.log(domainToUnicode("www.xn--xj8h.com")); // => www.๐Ÿ•.com

Thanks to @nektro for adding these APIs!

Fixed: child_process could timeout early

We fixed a bug where spawned child_process would timeout early when timeout was defined. This did not affect code where the timeout was not defined.

import { spawn } from "node:child_process";

const start = performance.now();
await new Promise((resolve, reject) => {
  const child = spawn("sleep", ["1000"], { timeout: 1000 });
  child.on("error", reject);
  child.on("exit", resolve);
});
const duration = performance.now() - start;

console.log(duration); // ~10ms instead of ~1000ms

Thanks to @Electroid for fixing this bug!

Fixed: socket event not firing in node:http

We fixed a bug where the socket event would not fire in node:http when a client connected to a server.

import { request } from "http";

const request = request("http://localhost:8080");
await new Promise((resolve, reject) => {
  request.on("error", reject);
  request.on("socket", function onSocket(socket) {
    request.destroy();
    console.log(socket);
    resolve();
  });
});

Fixed: Crash with invalid arguments to Bun.serve()

We fixed a bug where Bun.serve() would crash if the Bun.serve() options were invalid in some cases. It should have thrown an error instead.

Thanks to @paperdave for fixing this bug!

Fixed: Crash with expect() outside a test

We fixed a bug where expect() using an async resolver would crash if it was called outside of a test.

import { expect } from "bun:test";

expect(Bun.sleep(1000)).resolves.toBeTruthy();

Thanks to @paperdave for fixing this bug!

Fixed: Potential crash when fetch() received an invalid Location header

If the Location header received by fetch() pointed to an invalid URL, Bun would potentially crash. This has now been fixed.

Thanks to @nektro for fixing this bug!

Implemented: 2nd argument for URLSearchParams.delete & URLSearchParams.has

The URLSearchParams.prototype.delete and URLSearchParams.prototype.has methods get support for a second "value" argument. This allows you to delete or check for a specific value in a URLSearchParams.

const params = new URLSearchParams("a=1&a=2&b=3");
params.delete("a", 1);
params.delete("b", undefined);
params + ""; // => actual='' expected='a=2'

This feature was a recent addition to the Web Platform, and we've added it to Bun.

Fixed: .test.env not loading when NODE_ENV=test

We found a bug where the .test.env file would not load when NODE_ENV=test and a .production.env file also existed. This has been fixed, thanks to @nektro.

Fixed: Errors not buffered to stderr

We found a performance bug where Bun would not buffer writes when printing stack traces to stderr. This has now been fixed.

bun install bugfixes

Fixed: Various bugs with bunx

We also fixed various bugs with bunx:

  • bunx --bun would sometimes ignore the --bun flag, depending on the flag order.
  • bun x --bun would forward the --bun flag to the script, instead of Bun.
  • bun --bun create would crash and not work properly.
  • bunx <github> would sometimes hang.

Thanks to @paperdave for fixing these bugs!

Fixed: node-gyp would sometimes not run

A bug where bun install would not run lifecycle scripts when a package.json had both a postinstall script and a bindings.gyp file has been fixed. This bug impacted node-pty, among other packages.

Thanks to @dylan-conway for fixing this bug!

Fixed: bun pm cache rm now removes bunx cache

Previously, bun pm cache rm would not remove the node_modules cache for bunx. This has been fixed.

Internal: I/O architecture changes

In this release, we've reimplemented how Bun:

  • Spawns processes
  • Reads files (streaming)
  • Writes files (streaming)

These new implementations do a better job of preventing reads/writes from blocking the main thread, without paying the cost of moving all I/O to a threadpool. Peak memory usage should be lower, especially with node:stream & node:fs.

Please report any bugs you find when using Bun.file(path).stream(), fs.createReadStream, fs.createWriteStream, or Bun.spawn().

Windows support is close

We are close to shipping Windows support with Bun v1.1. Once Bun for Windows passes 95% of Bun's test suite, we will announce the release date.

Thank you to 18 contributors!

Full Changelog