Bun is an incredibly fast JavaScript runtime, bundler, transpiler, and package manager — all in one.
Bun v1.1.4 fixes 40 bugs (addressing 84 👍 reactions). bun run --filter <workspace> <script>
lets you run multiple workspace scripts in parallel. Reinstalls get up to 50% faster in bun install. Important reliability fixes to bun install. bun:sqlite supports using
for resource cleanup and has a few bugfixes. Memory leak impacting Next.js Standalone & Web Streams is fixed. Node.js compatibility improvements fs
and child_process
. Fix for "Connection closed" in fetch(). A few bugfixes for Bundows.
Previous releases
v1.1.3
Bun v1.1.3 fixes 5 bugs. bun install gets 50% faster on Windows. A bug that could cause bun install to hang in rare cases has been fixed. A bug where some errors in bun install would not produce a non-zero exit code has been fixed. A bug that could cause specific certain combinations of dependencies to fail to install has been fixed. A bug on Windows where CTRL + C on cmd.exe after exiting bun would not behave as expected has been fixed. A bug where missing permissions on Windows for reading a directory could lead to a crash has been fixed.v1.1.2
Bun v1.1.2 fixes 4 bugs (addressing 44 👍 reactions). EBUSY on Windows in vite dev, next dev, and saving bun.lockb has been fixed. Bun Shell gets support for seq, yes, basename and dirname. A TypeScript parsing edgecase has been fixed. A bug causing 'unreachable code' errors has been fixed. fs.watch on Windows has been rewritten to improve performance and reliability.v1.1.1
Bun v1.1.1 fixes 20 bugs (addressing 60 👍 reactions).v1.1.0
Bundows. Windows support is here! Plus, JSON IPC Node <-> Bun.
To install Bun:
curl -fsSL https://bun.sh/install | bash
npm install -g bun
powershell -c "irm bun.sh/install.ps1|iex"
scoop install 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
bun install fixes
bun --filter
runs workspace scripts in parallel
Say you have a monorepo with two packages: packages/api
and packages/frontend
, both with a dev
script that will start a local development server.
Normally, you would have to open two separate terminal tabs, cd into each package directory, and run bun dev
:
Using --filter
, you can run the dev
script in both packages at once, using glob patterns to filter which projects to run the script in:
bun --filter='*' dev
Both commands will be run in parallel, and you will see a nice terminal UI showing their respective outputs:
You can pass multiple filters to --filter
:
bun --filter 'packages/api' --filter 'packages/frontend' dev
You can think of this as a more powerful replacement for npm run --workspace <workspace> <script>
.
Thanks to pnpm for the inspiration, and to @gvilums for implementing this feature.
Up to 50% faster reinstalls in bun install
When dependencies in node_modules
have to be reinstalled (for example, because the version on-disk is different), bun install is now up to 50% faster.
In a repository with 450 MB of node_modules
on a Macbook Pro M3:
❯ hyperfine "bun install --ignore-scripts" "bun-1.1.3 install --ignore-scripts" --prepare="rm -rf node_modules/**/package.json" --warmup=2
Benchmark 1: bun install --ignore-scripts
Time (mean ± σ): 501.6 ms ± 15.6 ms [User: 18.0 ms, System: 1174.0 ms]
Range (min … max): 491.1 ms … 543.8 ms 10 runs
Benchmark 2: bun-1.1.3 install --ignore-scripts
Time (mean ± σ): 771.4 ms ± 13.4 ms [User: 13.9 ms, System: 616.6 ms]
Range (min … max): 756.0 ms … 800.4 ms 10 runs
Summary
bun install --ignore-scripts ran
1.54 ± 0.05 times faster than bun-1.1.3 install --ignore-scripts
We moved deleting the old package's files to a separate thread to speed up the wall-clock time and reduce blocking I/O on the main thread.
Fixed: Hoisting aliased packages
Bun was not hoisting aliased npm packages before. This meant we would install the same aliased packages multiple times in node_modules
unnecessarily.
This has been fixed, thanks to @dylan-conway.
Fixed: Sometimes flaky bun install
in CI environments
A bug that could cause bun install
to fail in CI environments sporadically has been fixed.
The code that waited for dependencies in node_modules
of dependencies within a child node_modules
folder was not correctly always waiting for the parent to finish installing before installing the children. This led to potentially creating the parent dependencies folder in node_modules, installing the package, and then deleting it.
This bug manifested most frequently when installing many different versions of the same package simultaneously when there was no cached version available on disk. For example, this bug could cause string-width
to potentially throw an ERR_REQUIRE_ESM
when used in Node.js.
Thanks to @dylan-conway for fixing this.
Node.js compatibility improvements
fs.close() callback is optional
Previously, the following code would work in Node.js but not in Bun:
import fs from "fs";
fs.open("file.txt", "r", (err, fd) => {
// missing the callback in the 2nd argument!
fs.close(fd);
});
Now, the callback is optional in Bun as well.
Thanks to @gvilums for fixing this.
fs.writeFile(fd, data) should not truncate
In Node.js, when fs.writeFile
is called with a file descriptor, it does not truncate the file. When called with a path, it does.
Previously in Bun, fs.writeFile
would truncate the file when called with a file descriptor or a path. This has been fixed to now match Node.js behavior and only truncate when called with a path.
import { writeFile } from "fs/promises";
import { openSync } from "fs";
const fd = openSync("file.txt", "w");
await writeFile(fd, "hello"); // does not truncate
await writeFile("file.txt", "hello"); // truncates
Thanks to @gvilums for fixing this.
FileHandle#appendFile appends
In Node.js, FileHandle#appendFile
appends to the file. Previously in Bun, it would truncate the file before appending. This has been fixed.
import { open } from "fs/promises";
const file = await open("file.txt", "a");
await file.appendFile("hello"); // appends
bun:sqlite improvmeents
New: using
Database & Statement
The using
syntax is now supported for Database
and Statement
objects in bun:sqlite. This syntax will automatically call Database#close
and Statement#finalize
when the scope ends.
import { Database } from "bun:sqlite";
{
// Automatically close the Database at the end of this scope
using db = new Database("file.db");
// Automatically finalize the statement at the end of this scope.
using query = db.query("SELECT * FROM users");
for (const row of query.all()) {
console.log(row);
}
}
using
is part of the stage3 TC39 proposal Explicit Resource Management.
New: Database#fileControl
method
The low-level sqlite3_file_control
method is now exposed in bun:sqlite as Database#fileControl
.
import { Database, constants } from "bun:sqlite";
const db = new Database();
// Ensure WAL mode is NOT persistent
// this prevents wal files from lingering after the database is closed
db.fileControl(constants.SQLITE_FCNTL_PERSIST_WAL, 0);
New: Database#close(throwOnError: boolean = false)
argument
You can now pass a throwOnError
argument to Database#close
to throw an error if the database cannot be closed for any reason.
import { Database, constants } from "bun:sqlite";
const db = new Database();
const query = db.query("SELECT * FROM users");
db.close(true); // "Database is locked"
db.close(false); // no error, stop new queries from being created
Internally, when throwOnError
is true, sqlite3_close
is called instead of sqlite3_close_v2
.
This is not a breaking change because previously close
did not accept any arguments, and the behavior remains the same if no arguments are passed. The argument defaults to false.
Fixed: Close database when garbage collected
When the Database
object gets garbage collecte due to no longer being in use, the Database
will now be closed in sqlite automatically.
Previously, bun:sqlite would only close databases automatically on process exit. This was not good enough.
Fixed: Bug with binding to duplicate column names in JOIN
A longstanding bug related to duplicate column names in JOIN queries when using bun:sqlite has been fixed.
import { Database } from "bun:sqlite";
const db = new Database();
db.query(
"CREATE TABLE Users (Id INTEGER PRIMARY KEY, Name VARCHAR(255));",
).run();
db.query(
"CREATE TABLE Cars (Id INTEGER PRIMARY KEY, Driver INTEGER, FOREIGN KEY (Driver) REFERENCES Users(Id))",
).run();
db.query('INSERT INTO Users (Id, Name) VALUES (1, "Alice");').run();
db.query("INSERT INTO Cars (Id, Driver) VALUES (1, 1);").run();
const car = db.query("SELECT * FROM Cars JOIN Users ON Driver=Users.Id").get();
console.log(car);
db.close();
Previously, the above code would incorrectly log:
{
Id: 1,
Driver: 1,
Name: 1,
}
Now, it correctly logs:
{
Driver: 1,
Id: 1,
Name: "Alice",
}
This matches the behavior of the popular better-sqlite3
package.
Thanks to @gvilums for fixing this, and to @Hanaasagi for the initial investigation.
Bundows improvements
windowsHide
& windowsVerbatimArguments
The Node.js child_process
API supports the windowsHide
and windowsVerbatimArguments
options. These options are now supported in Bun as well, thanks to @nektro.
Bun.serve() extra byte
A bug where Bun.serve() could potentially send an extra byte of duplicated data with certain input has been fixed, thanks to @cirospaciari.
This regression started in Bun v1.1.1 and we've improved our test coverage to prevent this from happening again.
Bun.which() case-insensitive file extension
On Windows, filenames are generally case-insensitive. Bun.which() now also matches case-insensitive file extensions on Windows. This means you can open cmd.EXE
as well as cmd.exe
(and all other permutations of case) on Windows.
--cwd
flag works on Windows
The --cwd
flag now works as expected on Windows.
bun --cwd=.\my-app run hey
This changes the current working directory to .\my-app
before running the hey
script. This saves you from having to cd
into the directory before running the script.
Runtime improvements
New: AbortSignal.any
Bun now supports AbortSignal.any
, which lets you create a new AbortSignal
that is aborted when any of the passed AbortSignal
are signaled. It's sort of like Promise.race
for AbortSignal
s.
const first = new AbortController().signal;
const second = new AbortController().signal;
fetch("https://example.com", {
signal: first,
});
fetch("https://example.com", {
signal: second,
});
const abortSignal = AbortSignal.any([first, second]);
// Cancel this when either `first` or `second` is aborted
await fetch("https://example.com/slow", { signal: abortSignal });
This code comes directly from WebKit/Safari, so thanks to the WebKit team for implementing this feature.
Fixed: Memory leak in Web Streams impacting Next.js
A memory leak in Web Streams has been fixed. This bug could cause Next.js Standalone to leak memory when responding to requests.
Thanks to @lithdew for fixing this.
Fixed: fetch() "Connection closed" bug
Some servers rely on TLS v1.2 renegotiation, which lets a server change how it authenticates a client after the connection has been established. This was deprecated in TLS v1.3, but many servers still use it. Previously, when encountering a server that used TLS renegotiation, Bun would throw a "Connection closed" error. We now allow TLS renegotiation for clients, but continue to not allow it for servers. For servers, TLS renegotiation is a DoS attack vector, BoringSSL does not support it, and is generally not recommended.
This bug sometimes manifested as receiving a Connection closed
error when using fetch()
in Bun.
Thanks to @cirospaciari for fixing this, and to @lithdew for narrowing down the issue.
Fixed: escaped newlines in shell commands
A bug where escaped newlines in shell commands did not match bash's behavior has been fixed, thanks to @zackradisic. This bug impacted bun run
on Windows as well as Bun.$
at runtime. Thanks to @zackradisic for fixing this.
Thanks to 11 contributors!
- @cirospaciari
- @DaleSeo
- @dylan-conway
- @evanshortiss
- @gvilums
- @Jarred-Sumner
- @jdalton
- @jdfwarrior
- @nektro
- @SunsetTechuila
- @zackradisic