Bun v1.0.19 fixes 26 bugs (addressing 92 👍 reactions). Use @types/bun instead of bun-types. Fixes "lockfile had changes, but is frozen" bug. bcrypt & argon2 packages now work. setTimeout & setInterval get 4x higher throughput. module mocks in bun:test resolve specifiers. Optimized spawnSync() for large stdio on Linux. Bun.peek() gets 90x faster, expect(map1).toEqual(map2) gets 100x faster. Bugfixes to NAPI, bun install, and Node.js compatibility improvements
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:
v1.0.14-Bun.Glob, a fast API for matching files and strings using glob patterns. It also fixes a race condition when extracting dependencies duringbun install, improves TypeScript module resolution innode_modules, and makes error messages easier to read.v1.0.15- Fixes 23 bugs (addressing 117 👍 reactions),tscstarts 2x faster. StableWebSocketclient, syntax-highlighted errors, cleaner stack traces, add custom test matchers withexpect.extend()+ additional expect matchers.v1.0.16- Fixes 49 bugs (addressing 38 👍 reactions). Concurrent IO for Bun.file & Bun.write gets 3x faster and now supports Google Cloud Run & Vercel, Bun.write auto-creates the parent directory if it doesn't exist,expect.extendinside of preload works,napi_create_objectgets 2.5x faster, bugfix for module resolution impacting Astro v4 and p-limit, console.log bugfixesv1.0.17- Fixes 15 bugs (addressing 152 👍 reactions). bun install postinstall scripts run for top 500 packages,bunx supabasestarts 30x faster thannpx supabase,bunx esbuildstarts 50x faster thannpx esbuildand bugfixes to bun installv1.0.18- Fixes 27 bugs (addressing 28 👍 reactions). A hang impacting create-vite & create-next & stdin has been fixed. Lifecycle scripts reporting "node" or "node-gyp" not found has been fixed. expect().rejects works like Jest now, and more bug fixes
To install Bun:
curl -fsSL https://bun.sh/install | bashnpm install -g bunbrew tap oven-sh/bunbrew install bundocker pull oven/bundocker run --rm --init --ulimit memlock=-1:-1 oven/bunTo upgrade Bun:
bun upgradeRe-introducing @types/bun (formerly bun-types)
@types/bun gives you type definitions for Bun. It's a separate package from Bun itself, to make it easier to use Bun with your text editor or IDE.
Previously, this package was called bun-types and there were a lot of issues with it:
- You had to set
typesin yourtsconfig.json, which broke loading packages using the@typesfolder convention - We embedded a slightly modified version of
@types/node, which frequently conflicted with the real@types/nodepackage - It didn't "just work" with TypeScript unless you configured it correctly
- DOM/Web types would occasionally conflict with Bun's types
Now, @types/bun should just work. It re-exports the real @types/node package so there's no conflicts. Since it's now in the @types namespace, it should work without breaking @types/* packages.
To install @types/bun:
bun add -d @types/bunOr you can ue bun init:
bun initbcrypt & argon2 packages now work
N-API compatibility improvements unlocked bcrypt and argon2 package support in Bun. These packages are widely used to securely hash & verify passwords.
Bun.password also lets you hash and verify passwords using either bcrypt or argon2 without any dependencies to install.
|
|
Fixed: "lockfile had changes, but is frozen" bug
The code path used by --frozen-lockfile to detect whether a lockfile changed sometimes incorrectly reported that the lockfile changed when it didn't. This would cause errors like:
error: lockfile had changes, but is frozen
To fix this, we've changed how we define "frozen". Instead of relying on input from the filesystem which can potentially change for unrelated reasons, we've switched it to using a hash of the package names and their versions sorted alphabetically with their version numbers. We think this is a more reliable approach.
To see what the hash of your lockfile is, run:
bun pm hash-stringView example output
setTimeout & setInterval get 4x higher throughput
Bun's setTimeout and setInterval implementations are now 4x faster on Linux x64. We've added a timer heap to more efficiently manage timers.
❯ bun setTimeout-leak-test.js
Executed 1003520 timers in 421.560553 ms
❯ bun-1.0.18 setTimeout-leak-test.js
Executed 1003520 timers in 2287.405973 ms
Thanks to @mitchellh's libxev for the timer heap implementation.
Why is timer performance important?
You might be thinking something like:
"Timers delay code execution. Why does it matter if it's fast?"
Timer scheduling has a significant performance impact on your code, and many libraries use timers to schedule work with a slight delay. Timers don't have to trigger much faster, but timer scheduling needs to be fast.
Bun's previous timer implementation was somewhat irresponsible. On Linux, it created a timerfd for every timer. This means every timer involves multiple system-calls and occupies a file descriptor. That's a lot of overhead for code which potentially runs very frequently.
Bun's new timer implementation uses a timer heap. This is a data structure that allows us to efficiently schedule potentially millions of timers.
Fixed: setInterval sometimes still ran after clearInterval
There was a bug where an already-cancelled call to setInterval would occasionally still run one time. This was fixed along the way to rewriting the timer implementation.
Better error for using await outside an async function
We've added a better error message when you use await outside of an async function.
❯ bun file.js # after
3 | await fetch("https://example.com")
^
error: "await" can only be used inside an "async" function
at file.js:3:9
2 | function ohNo() {
^
note: Consider adding the "async" keyword here
at file.js:2:1
Before, it would just say:
❯ bun-1.0.18 file.js # before
3 | await fetch("https://example.com")
^
error: Expected ";" but found "fetch"
at file.js:3:9
Optimized Bun.spawnSync for large input on Linux
On Linux, Bun.spawnSync now gets smarter about how it reads and writes data from child processes. We've switched from a pipe which must be read & written in a loop by the parent process to an in-memory file descriptor which does not cause processes to block when reading or writing large amounts of data. This also lets us avoid cloning the data from the child process to the parent process which can be expensive for large amounts of data.
This change makes Bun.spawnSync 50% faster when the child process has a large amount of output.
Bun.peek() gets 90x faster
Bun.peek(promise) lets you read a promise's value without waiting for it to resolve, if it's no longer pending. This is useful to avoid microtasks and improve performance.
We've switched the implementation from relying on C++ SPI to using a JavaScriptCore bytecode intrinsic which makes it 90x faster.
Thanks to @paperclover
expect(map1).toEqual(map2) gets 100x faster
We've optimized the implementation of expect(...).toEqual when comparing Map instances. This makes it 100x faster for maps. This also makes it faster for Set instances.
We've also fixed a bug where toEqual on large maps would sometimes incorrectly report the maps are not equal.
module mocks in bun:test resolve specifiers
Bun supports mocking modules in bun:test using the mock.module function. Previously, the specifier argument had to exactly match the resolved module specifier used when loading the overridden module.
This was very confusing! People usually don't think about the difference between a resolved module specifier and a module specifier, and that means it seemed to not work when it actually did. Since ES Modules resolve and link modules before evaluating them, the resolved module specifier is usually different from the module specifier you use in import statements.
Now, mock.module resolves the specifier before mocking the module. This means you can use the module specifier (the path you put in import statements) instead of the resolved module specifier (the path you see in error messages).
import { mock, test, expect } from "bun:test";
import _ from "lodash";
// Before: you had to resolve it yourself:
mock.module(require.resolve("lodash"), () => ({ default: "mocked" }));
// Now: you can use the module specifier:
mock.module("lodash", () => ({ default: "mocked" }));
test("lodash is mocked", () => {
expect(_).toEqual("mocked");
});Log slow postinstall scripts
If a post-install script takes longer than 500ms to run, bun install will now log it as a warning. This is useful to identify slow post-install scripts.
bun add v1.0.19 (7e59f287)
installed re2@1.20.9
+warn: re2's install script took 57.7s
92 packages installed [58.20s]
To avoid cluttering your terminal scrollback, we only log the slowest post-install script (not all of them).
Thanks to @paperclover.
Fixed: potential hang when running post-install scripts
There was an event loop bug that could cause bun install to potentially hang (by not realizing they've exited) when running post-install scripts. This was fixed, thanks to @dylan-conway.
bun install --verbose now streams post-install script output
When running bun install --verbose, post-install script output is now streamed to the terminal instead of buffered and printed at the end. This makes it easier to see what's happening. Thanks to @dylan-conway for implementing this.
Fixed: missing progress bar in post-install script output
In certain cases, bun install would not show a progress bar while the post-install scripts are running. This has been fixed, thanks to @dylan-conway.
Fixed: stringifying SHA1, SHA256, MD5 hashes sometimes output too long of a string
A bug when encoding the output of a SHA1, SHA256, or MD5 hash as a hex or base64 string would sometimes output a string that was longer than the contents of the hash. This is now fixed.
This impacted:
Bun.CryptoHashercreateHashinnode:crypto
Upgraded SQLite from v3.38.5 to v3.44.2
bun:sqlite is a fast SQLite client built into Bun. On Linux, bun:sqlite is statically linked which means we embed the SQLite library into Bun itself. This means you don't need to install SQLite on your system to use it.
We've upgraded the embedded SQLite library from v3.38.5 to v3.44.2. You can see the full changelog here.
Fixed: TypeScript parser edgecase
Previously, the following input would incorrectly fail to parse:
const a = <T = any>(): T => null as T;
const b = a<string>
This is now fixed. Thanks to @paperclover for fixing this.
Fixed: crash in bun init
A crash that sometimes occurred in bun init has been fixed, thanks to @paperclover.
Fixed: regression with $NODE_ENV
In Bun v1.0.18 (the previous version), we accidentally removed setting a default value for NODE_ENV. This breaking change was not meant to be included in Bun v1.01.8. We may do a breaking change in the future to unset a default value (outside bun test), but we will not do this in a patch release.
Thanks to @paperclover for fixing this.
Fixed: printing bug with holey arrays
There was a bug where printing holey arrays would miss the delimiter & comma. This is now fixed, thanks to @amartin96.
After:
❯ bun -e 'console.log([1,,,2,1,3])' # After
[ 1, 2 x empty items, 2, 1, 3 ]
Before:
❯ bun-1.0.18 -e 'console.log([1,,,2,1,3])' # Before
[ 12 x empty items, 2, 1, 3 ]
New matcher in bun:test expect().toContainEqual()
We've added a new matcher to bun:test called toContainEqual. This is similar to toContain, but it uses toEqual to compare the values instead of ===.
import { test, expect } from "bun:test";
test("toContainEqual", () => {
expect("hello world").toContainEqual("hello");
expect("hello world").not.toContainEqual("jello");
});
Thanks to @Electroid for implementing this.
Credits
We love seeing new contributors! Here are the 9 people who made their first contribution to Bun in this release:
- @Osmose made their first contribution in #7275
- @scotttrinh made their first contribution in #7686
- @vlechemin made their first contribution in #7688
- @dotspencer made their first contribution in #7727
- @spicyzboss made their first contribution in #7737
- @bjon made their first contribution in #7738
- @amartin96 made their first contribution in #7751
- @sirhypernova made their first contribution in #7760