Bun

Bun v0.5.7


Ashcon Partovi · February 24, 2023

Bun v0.5.7 introduces FormData support, git dependencies, and AbortSignal with fetch(), setTimeout() is now more compatible with Node.js, bun wiptest is now bun test — with pretty-printed diffs! — and improved support on AWS Lambda and GitHub Actions.

# Install using curl
curl -fsSL https://bun.sh/install | bash

# Install using npm
# npm install -g bun

# Upgrade
bun upgrade

FormData support

Bun now supports FormData, a standard Web API for working with form fields and files in multipart uploads. You can add a string as a field or a Blob as a file.

const formData = new FormData();
formData.set("attachment-id", crypto.randomUUID());
formData.set("attachment", Bun.file("./package.json"));
const response = await fetch("https://example.com/upload", {
  method: "POST",
  body: formData,
});

You can also parse FormData from a Request or Response.

export default {
  async fetch(request: Request): Promise<Response> {
    const formData = await request.formData();
    const file = formData.get("attachment");
    // ...
    return new Response(file);
  },
};

In Bun, response.formData() runs:

  • 25x faster than Node v19.6.0
  • 4x faster than Deno v1.30.3
image

View benchmark

Git dependencies

Bun now supports git dependencies in package.json. Bun accepts a variety of git dependency formats, including github, git, git+ssh, git+https, and many more.

{
  "dependencies": {
    "zod": "github:colinhacks/zod",
    "lodash": "git@github.com:lodash/lodash.git#4.17.21"
  }
}

You can also add a git dependency using bun install.

bun install git@github.com:moment/moment.git

Changes to setTimeout()

The Web standard setTimeout() returns a number, which represents a timeout ID. The Node.js implementation of setTimeout() returns a Timeout object, which has methods like ref() and unref(), but is coercable to a number.

We (reluctantly) decided to change Bun's implementation to match Node.js because there are many npm packages that depend on this legacy behaviour.

const timeout = setTimeout(() => {
  process.abort(); // this is not called, see `unref()` below
}, 1000);

timeout.unref();

// For compatibility, it still works as a number
const timeoutId = +timeout; // 1

We also improved the console.log() formatting of the Timeout object.

image

AbortSignal with fetch()

You can now cancel a fetch() request using an AbortSignal. This is useful for timeouts or when you need to cancel a request before a response is received.

await fetch("https://example.com", {
  // Abort if the response is not received after 1 second
  signal: AbortSignal.timeout(1000),
});

You can also use an AbortSignal when receiving a Request from the HTTP server.

export default {
  async fetch(request: Request): Promise<Response> {
    request.signal.addEventListener("abort", () => {
      console.log("Client aborted the request");
    });
    // ...
    return new Response();
  },
};

bun wiptest is now bun test

It's time for bun wiptest to graduate to bun test.

Pretty-printed diffs

bun test now supports pretty-printed diffs, thanks to @dylan-conway for implementing and @SuperAuguste for porting the diff-match-patch algorithm to Zig.

Now:

error: expect(received).toEqual(expected)

  {
    abc: 123,
+   def: 456
-   def: 789
  }

- Expected  - 1
+ Received  + 1

Before:

error: Expected values to be equal:
	Expected: {
  abc: 123,
  def: 789
}
	Received: {
  abc: 123,
  def: 456
}

Auto-import for jest globals

bun test now automatically imports test() and expect(). This also works for the other Jest globals, including: describe, beforeAll, afterAll, and more.

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

test("that it auto-imports expect()", () => {
  expect({
    abc: 123,
    def: 456,
  }).toEqual({
    abc: 123,
    def: 789,
  });
});

We still recommended that you import from bun:test, but if you have existing tests using Jest, you probably rely on its globals.

New methods on Set

The Set class now has more built-in methods, thanks to @kmiller68 at WebKit.

const a = new Set([1, 2, 3]);
const b = new Set([1, 3, 4, 5]);
const c = new Set([1, 3]);

console.log(a.union(b)); // [1, 2, 3, 4, 5]
console.log(a.intersection(b)); // [1, 3]
console.log(a.difference(b)); // [2]
console.log(a.symmetricDifference(b)); // [2, 4, 5]

AWS Lambda support

Bun can now run AWS Lambda using a custom layer.

The layer will detect when an event is an HTTP request and transform it into a standard Request. This means you can test your Lambda locally using bun run, without any code changes.

export default {
  async fetch(request: Request): Promise<Response> {
    console.log(request.headers.get("x-amzn-function-arn"));
    // ...
    return new Response("Hello from Lambda!", {
      status: 200,
      headers: {
        "Content-Type": "text/plain",
      },
    });
  },
};

For events that are not HTTP requests, like a S3 or SQS trigger, the event will be in the body of the Request.

export default {
  async fetch(request: Request): Promise<Response> {
    const event = await request.json();
    // ...
    return new Response();
  },
};

GitHub Action support

There is a new release of the setup-bun GitHub Action, which you can also find on the GitHub Marketplace. Thanks to @xHyroM for maintaining the initial version of it.

- uses: oven-sh/setup-bun@v1
  with:
    bun-version: latest
- uses: oven-sh/setup-bun@v1
  with:
    bun-version: "0.5.7"

Now, with the newly added support for git dependencies, we encourage you to try this out in your GitHub CI and see much time you can save with bun install.

steps:
  - uses: actions/checkout@v3
  - uses: actions/setup-node@v3
    with:
      node-version: 16
+ - uses: oven-sh/setup-bun@v1
+   with:
+     bun-version: latest
+  - run: bun install
-  - run: npm install

Changelog

523b112Added auto-import for jest globals in bun test by @Jarred-Sumner
#2029Fixed fs.createWriteStream() from exiting early by @alexlamsl
995880aEnabled more Set methods by @Jarred-Sumner
#2039Fixed "Duplicate dependency" error for peerDependencies by @alexlamsl
#2044Fixed incorrect build instructions for macOS by @ekzhang
#2041Fixed syntax error when regex was present in package.json by @jwhear
675529bFixed a bug where Buffer was not assignable by @Jarred-Sumner
#2054Implemented napi_fatal_exception by @ThatOneBro
#2045Fixed bun install crash during non-install script execution by @alexlamsl
83473c6Defined a fallback for globalPaths in require("module") by @Jarred-Sumner
#2057Fixed a bug where server.listen() did not return the server by @michalwarda
bb2aaa3Enabled release signing by @Electroid
#2059Implemented git://github.com dependencies by @alexlamsl
#2051Implemented FormData by @Jarred-Sumner
0db8cdfFixed fetch() not sending a default Content-Type header by @Jarred-Sumner
#2061Implemented napi_get_value_bigint_words by @ThatOneBro
#2062Allowed { port: 0 } in Bun.serve() to use a random port by @michalwarda
37186f4Improved console.log() output for FormData by @Jarred-Sumner
#2047Disallowed bodies when fetch() method is GET, HEAD, or OPTIONS by @ekzhang
#1798Exported fs.ReadStream and fs.WriteStream by @ThatOneBro
#2074Improved validation of package.json by @alexlamsl
4dc6bf1Added workarounds for node:tls and node:worker_threads by @Jarred-Sumner
#2076Fixed a bug where network-delayed .bin scripts were not installed by @alexlamsl
f19e3d6Added a workaround for node:async_hooks by @Jarred-Sumner
#1971Implemented ED25519 for WebCrypto by @Jarred-Sumner with thanks to @panva
0d7cea6Added a workaround for eval("__dirname") by @Jarred-Sumner
1125728Fixed bugs with napi_create_threadsafe_function by @Jarred-Sumner
#2087Improved documentation to build on macOS by @controversial
#2089Fixed writeFileSync({ flag: undefined }) from not working by @jwhear
#2088Implemented os.machine() for Linux by @jwhear
#2086Supported yarn-like workspaces by @Jarred-Sumner
56b75dbImplemented faster Buffer.byteLength("latin1") by @Jarred-Sumner
#2095Fixed bun add of packages with capital letters by @alexlamsl
#2096Fixed String.replace() with non-ASCII characters by @jwhear
#2094Supported git dependencies by @alexlamsl
#2066Fixed a crash with invalid encoding in fetch() headers by @jwhear
1106c8eFixed parsing of fs flags by @Jarred-Sumner
#1378Implemented os.machine() for macOS by @sno2
#2104Fixed a change in how URLs are printed by @MichaReiser
c006a7fLoad .env.production when NODE_ENV=production by @Jarred-Sumner
#2122Added a pretty string differ to bun test by @dylan-conway
#2124Supported git dependencies by @alexlamsl
#2009Implemented a runtime layer for Bun on AWS Lambda by @Electroid
#2128Fixed output in child_process.exec() by @ThatOneBro
#2131Renamed bun wiptest to bun test by @dylan-conway
#2126Fixed glibc error in alpine Docker image by @WebReflection
#2135Improved various types for bun-types by @colinhacks
2a1558eSupported Node.js-style setTimeout() by @Jarred-Sumner
#2097Supported AbortSignal in fetch() by @cirospaciari