Bun is an incredibly fast JavaScript runtime, bundler, transpiler, and package manager โ all in one. In case you missed it, here are some of the recent changes to Bun.
This release fixes 30 bugs, adds support for multi-statement queries in bun:sqlite, makes bun --watch more reliable in longer-running sessions, Bun.FileSystemRouter now supports more than 64 routes, fixes a bug with expect().toStrictEqual(), fixes 2 bugs with error.stack, fixes a bug with fileURLToPath, improves Node.js compatibility
Previous releases
v1.0.25
fixes 4 bugs, adds vm.createScript. Fixes a crash in fs.readFile, a crash in Bun.file().text(), a crash in IPC, and a transpiler bug involving loose equalsv1.0.24
fixes 9 bugs and adds Bun Shell, a fast cross-platform shell with seamless JavaScript interop. Fixes a socket timeout bug, a potential crash when socket closes, a Node.js compatibility issue with Hapi, a process.exit bug, and bun install binlinking bug, bun inspect regression, and bun:test expect().toContain bugv1.0.23
fixes 40 bugs (addressing 194 ๐ reactions). import & embed sqlite databases in Bun, Resource Management ('using' TC39 stage3) support, bundler improvements when building for Node.js, bugfix for peer dependency resolution, semver bugfix, 4% faster TCP on linux, Node.js compatibility improvements and more"
To install Bun:
curl -fsSL https://bun.sh/install | bash
npm install -g bun
brew tap oven-sh/bun
brew install bun
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun
To upgrade Bun:
bun upgrade
Multi-statement queries in bun:sqlite
bun:sqlite
gets support for multi-statement queries. This allows you to run multiple SQL statements in a single call to db.run()
delimited by a ;
, similar to how it works in the sqlite
command-line tool.
import { Database } from "bun:sqlite";
const db = new Database(":memory:");
db.run(`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT
);
INSERT INTO users (name) VALUES ("Alice");
INSERT INTO users (name) VALUES ("Bob");
`);
const names = db
.query("SELECT name FROM users")
.all()
.map(({ name }) => name)
.join(", ");
console.log(names); // Alice, Bob
Only Database.prototype.run
and ``Database.prototype.execsupport multi-statement queries.
db.queryand
db.prepare` do not.
bun --watch reliability improvement
bun --watch
now defensively closes all file descriptors on reload. Filesystem watchers inherently need to keep many file descriptors open when watching many files, but keeping file descriptors open for a long time can lead to resource exhaustion and many other issues. Bun already set O_CLOEXEC
internally, but that doesn't always mean all file descriptors closed.
Part of what makes bun --watch
fast is we immediately reload the entire process when an imported file changes. There's very little work that happens between the file change and the process reload. This is in contrast to other tools that might recompile the file to check for changes, and only re-run the process on change.
On Linux, Bun now uses the close_range(2)
system call to close all file descriptors > 8 before reloading the process. This reliably ensures that all file descriptors are closed (for those of you running modern Linux kernels).
On macOS, we use the POSIX_SPAWN_CLOEXEC_DEFAULT
flag to close all file descriptors on spawn. We also fixed an issue where signals were not being reset to their default behavior on reload.
abort-controller
polyfill now uses native AbortController
The popular abort-controller
npm package polyfill now uses the native AbortController
in Bun instead of the polyfill.
This fixes an issue where Bun would report an error like "Expected signal to be an AbortSignal"
when a library used the abort-controller
polyfill with fetch
or Request
or Response
.
The abort-controller
polyfill is a polyfill for the AbortController
and AbortSignal
web APIs
Fixed: Bun.FileSystemRouter now supports more than 64 routes
Bun.FileSystemRouter is Bun's built-in Next.js pages-inspired filesystem router. It now supports more than 64 routes.
Previously, Bun would throw an uncatchable exception when you tried to use more than 64 routes. This was caused by an assertion failure in JavascriptCore when an object is defined with more than 63 "inline" properties. This has been fixed.
Fixed: error.stack sometimes undefined
Bun implements the V8 Stack Trace API (despite Bun using the JavaScriptCore engine), which adds methods like Error.prepareStackTrace
and Error.captureStackTrace
to the Error
object.
There was a bug where error.stack
was sometimes undefined
when it should have been a string. This has been fixed.
This bug impacted Firebase & Google Cloud libraries when they were about to log an error. It caused these libraries to throw a different error while trying to log the error, which was not helpful.
Fixed: error.stack CallSite lineNumber was sometimes negative
The following would sometimes print negative numbers:
Error.prepareStackTrace = (error, stack) => {
return [stack[0].getLineNumber(), stack[0].getColumnNumber()];
};
const error = new Error();
console.log(error.stack);
Bun returned negative numbers when the line number was not available. This unfortunately broke the popular source-map-support
library since it asserts that line and column numbers are positive integers. This has been "fixed" by never returning negative numbers.
Fixed: Error.prepareStackTrace
is now a function by default
In Node.js, Error.prepareStackTrace
is a function by default. In Bun, it was undefined
by default. This has been fixed.
The default Error.prepareStackTrace
function does what you would expect: it returns a string of the stack trace. You can continue to set Error.prepareStackTrace
to a custom function to customize the stack trace, or to undefined
(in which case the default function is used).
Fixed: module.path
is now __dirname
instead of module.id
In Node.js, the module
object has a path
property which is supposed to be the directory of the module, equivalent to __dirname
. In Bun, module.path
was incorrectly an alias for module.id
. This has been fixed.
Fixed: expect(a).toStrictEqual(b)
with deleted properties
A bug in bun:test
's expect.toStrictEqual
implementation caused it to behave incorrectly when comparing objects with deleted properties. This has been fixed, thanks to @dylan-conway.
import { test, expect } from "bun:test";
test("expect.toStrictEqual", () => {
const a = { a: 1, b: 2 };
const b = { a: 1, b: 2 };
delete b.b;
expect(a).toStrictEqual(b);
});
Previously, this would throw an error with a confusingly empty diff:
hey.test.ts:
2 |
3 | test("expect.toStrictEqual", () => {
4 | var obj1 = { a: 1 };
5 | var obj2 = {};
6 | delete obj1.a;
7 | expect(obj1).toStrictEqual(obj2);
^
error: expect(received).toStrictEqual(expected)
{}
- Expected - 0
+ Received + 0
at hey.test.ts:7:3
โ expect.toStrictEqual [0.29ms]
Now it correctly passes.
This happened because toStrictEqual used a fast path that failed to handle deleted properties correctly in some cases.
Fixed: event loop scheduling bug in Bun.serve() websockets
We've made some infrastructure tweaks to ensure that microtasks are always drained after event loop callbacks are executed. There was a bug where we skipped doing this in websockets, in Bun.spawn(), and in IPC handlers. Neglecting to drain the microtask queue can cause very high memory growth until the microtasks get drained (imagine if you just kept adding to a queue without ever removing anything).
Fixed: new Response(Bun.file()) sometimes logged an error to stderr
When you passed a Bun.file()
to new Response()
to Bun.serve()
connected to HTTP (not HTTPS), if the client aborted the request at the right time, Bun would log Error: NOTCONN
to stderr with no way to suppress it. This was confusing and unhelpful. Aborting a request is a normal part of the web, and Bun should not log an unsupressable error when it happens.
Windows is happening on February 15th
78% of Bun's tests pass on Windows, but it's still not enough to release.
Most of the changes in this release were Windows-related, but this changelog excludes that since its not "released" yet.