This release fixes 141 issues (addressing 429 👍) and includes many reliability improvements throughout the runtime, the bundler, and the dev server.
To install Bun
curl -fsSL https://bun.sh/install | bashnpm install -g bunpowershell -c "irm bun.sh/install.ps1|iex"scoop install bunbrew tap oven-sh/bunbrew install bundocker pull oven/bundocker run --rm --init --ulimit memlock=-1:-1 oven/bunTo upgrade Bun
bun upgradeReduced idle CPU usage
Over-scheduling the garbage collector when idling had a serious impact on idle CPU usage.
In the next version of Bun
— Jarred Sumner (@jarredsumner) August 3, 2025
Idle CPU time is reduced pic.twitter.com/MbBvbWgMew
This change had a neutral impact on memory usage.
Automatic yarn.lock migration
bun install will now automatically migrate your yarn.lock (v1) file to a bun.lock file.
In the next version of Bun
— Bun (@bunjavascript) July 29, 2025
bun install now automatically migrates from yarn.lock -> bun.lock, preserving resolved dependency versions pic.twitter.com/6fq80Xz3Dy
Thanks to @RiskyMH for the contribution
40x faster AbortSignal.timeout
We rewrote AbortSignal.timeout to use the same underlying implementation as setTimeout. This makes it 40x faster.
Improved bun:test diffing
The diffing output in bun:test has been redesigned for improved readability.
Whitespace differences are highlighted.
Several edgecases involving non-ascii characters and numerous other bugs have been fixed.
Thanks to @pfgithub for the contribution!
New bun:test matchers for return values
Three new bun:test matchers have been added for asserting the return values of mock functions: toHaveReturnedWith, toHaveLastReturnedWith, and toHaveNthReturnedWith. These matchers use deep equality, similar to toEqual(), and support asymmetric matchers.
- toHaveReturnedWith(): Checks if the mock function has returned a specific value in any of its calls.
- toHaveLastReturnedWith(): Checks the return value of the most recent call.
- toHaveNthReturnedWith(): Checks the return value of a specific call (1-indexed).
import { test, expect, mock } from "bun:test";
test("toHaveReturnedWith", () => {
  const returnsAnObject = mock(() => ({ a: 1 }));
  returnsAnObject();
  expect(returnsAnObject).toHaveReturnedWith({ a: 1 });
});
test("toHaveLastReturnedWith", () => {
  const returnsAString = mock((i) => `call ${i}`);
  returnsAString(1);
  returnsAString(2);
  expect(returnsAString).toHaveLastReturnedWith("call 2");
});
test("toHaveNthReturnedWith", () => {
  const returnsANumber = mock((i) => i * 10);
  returnsANumber(1);
  returnsANumber(2);
  returnsANumber(3);
  expect(returnsANumber).toHaveNthReturnedWith(2, 20);
});
Thanks to @dylan-conway for the contribution!
Test your types with expectTypeOf
bun:test now includes expectTypeOf for asserting TypeScript types, with an API compatible with Vitest.
These assertions are no-ops at runtime; they are checked by the TypeScript compiler. To verify your type tests, run bunx tsc --noEmit.
import { expectTypeOf, test } from "bun:test";
test("type-level tests", () => {
  // Basic type assertions
  expectTypeOf("hello").toBeString();
  expectTypeOf(123).toBeNumber();
  // Check object shapes
  expectTypeOf({ a: 1, b: "2" }).toMatchObjectType<{ a: number }>();
  // Assert function parameter and return types
  function add(a: number, b: number): number {
    return a + b;
  }
  expectTypeOf(add).parameters.toEqualTypeOf<[number, number]>();
  expectTypeOf(add).returns.toBeNumber();
});
Thanks to @pfgithub for the contribution
mock.clearAllMocks() for bun:test
The bun:test module now implements mock.clearAllMocks(), a function to reset the state of all mocked functions. This function clears the .mock.calls and .mock.results properties of all mocks, but importantly, it does not restore their original implementations.
This is useful for resetting mock states between tests, for instance in a global setup file, without needing to manually track and clear each individual mock.
import { test, mock, expect } from "bun:test";
const random = mock(() => Math.random());
test("clearing all mocks", () => {
  random();
  expect(random).toHaveBeenCalledTimes(1);
  // Reset the state of all mocks
  mock.clearAllMocks();
  expect(random).toHaveBeenCalledTimes(0);
  // The mock implementation is preserved
  expect(typeof random()).toBe("number");
  expect(random).toHaveBeenCalledTimes(1);
});
Thanks to @pfgithub for the contribution
bun outdated and bun update now supports --recursive
bun outdated and bun update --interactive now have improved support for workspaces, making it easier to manage dependencies in monorepos.
You can now run these commands across all workspaces using the -r or --recursive flag.
# See outdated packages in all workspacesbun outdated --recursive
# Interactively update packages in all workspacesbun update -i -rWhen running bun update -i in a monorepo, a new "Workspace" column will be displayed, showing which workspace a dependency belongs to:
bun update -i --recursive
dependencies             Current  Target  Latest   Workspace
  ❯ □ @types/node        24.1.0   24.2.1  24.2.1   bun-typesAdditionally, the --filter flag is now supported in bun update -i, allowing you to scope updates to specific workspaces.
# Interactively update dependencies only in the "my-app" workspacebun update -i --filter="my-app"This also fixes issues where bun update would not correctly handle catalog dependencies. Additionally bun outdated and bun update -i shows which packages use the catelog in the workspace column.
Thanks to @RiskyMH for the contribution
Automatic ETag and If-None-Match in static routes of Bun.serve
Bun.serve now automatically generates ETag headers for static routes defined in the static option. When a client sends an If-None-Match header, Bun compares the ETag and sends a 304 Not Modified response if the content is unchanged. This improves caching efficiency and saves bandwidth, with no code changes required to enable it.
const server = Bun.serve({
  port: 0,
  routes: {
    "/latest.json": Response.json({ ...myBigObject }),
  },
});
const url = new URL("/latest.json", server.url);
const etag = await fetch(url).then((res) => res.headers.get("etag"));
const { status } = await fetch(url, {
  headers: {
    "If-None-Match": etag,
  },
});
console.log({ status, etag });
Windows long path support
Bun now consistently supports file paths longer than 260 characters on Windows. This is enabled via an application manifest, removing a common source of file-related errors in projects with deep directory structures or long file names.
import { mkdirSync, existsSync, rmSync } from "fs";
import { join } from "path";
// This path is longer than 260 characters
const longPath = join("C:\\", "a".repeat(270));
// This could've previously failed on Windows
mkdirSync(longPath, { recursive: true });
console.log(`Exists: ${existsSync(longPath)}`); // Exists: true
rmSync(longPath, { recursive: true, force: true });
Previously, supporting long file paths on Windows involved extremely complicated file path namespacing we internally added to most of our code. Now it's much simpler, since the Win32 API supports long paths natively.
WebAssembly.compileStreaming and WebAssembly.instantiateStreaming
Bun now supports WebAssembly.compileStreaming() and WebAssembly.instantiateStreaming(). These APIs allow you to compile and instantiate a WebAssembly module directly from a streaming source, like the Response from a fetch() call.
This approach is more efficient than the non-streaming alternatives (WebAssembly.compile and WebAssembly.instantiate), as it avoids buffering the entire Wasm module into memory. Compilation can start as soon as the first bytes are received, reducing latency and memory usage.
// Bun will stream the response body directly to the Wasm compiler.
const { instance, module } = await WebAssembly.instantiateStreaming(
  fetch("http://localhost:3000/add.wasm"),
);
// Use the instantiated module
console.log(instance.exports.add(2, 3)); // => 5
Thanks to @CountBleck for the contribution
Node.js compatibility improvements
- Fixed: A type error when assigning to require.maindue to an outdated type definition. Themainproperty is no longerreadonly.
- Fixed: Invalid source maperrors were incorrectly logged when runningnext dev --turbopack.
- Fixed: cancelling an HTTP request, such as by rapidly refreshing a page in next dev, could cause anERR_STREAM_ALREADY_FINISHEDerror
- Fixed: a thread-safety issue when using Zstandard streams with the zlibmodule.
- Fixed: a potential crash in node:crypto'sX509Certificatewhen invalid input was provided.
- Fixed: a hypothetical bug where an uncaught exception inside process.nextTickitself or a microtask would not be reported
- Fixed: memory leak in fs.mkdirandfs.mkdirSyncwith{ recursive: true }has been resolved.
- Fixed: missing [Symbol.asyncIterator]inprocess.stdoutandprocess.stderrwhen it's a TTY or pipe. This bug impacted some users of Claude Code on Linux.
Bun shell fixes
- Fixed: a crash in bun shellwhen using pipelines with built-in commands that exit immediately
- Fixed: $.braces()now supports patterns containing Unicode characters and more deeply nested expansions.
- Fixed: Shell lexer would incorrectly display the =token as+in error messages.
- Fixed: a crash when parsing invalid syntax in certain cases.
Bundler bugfixes
- Fixed: a stack overflow in the JavaScript parser when parsing deeply nested expressions. This was resolved by refactoring the parser to use less stack space, preventing crashes with long chains of member accesses or function calls.
- Fixed: a bug where bun buildwould generate invalid code for cyclic imports containing a top-levelawaitdependency, causing a syntax error.
bun install bugfixes
- Fixed: a bug with --linker=isolatedwhen running lifecycle scripts with paths that contain non-ASCII characters.
- Fixed: a crash when a permissions error during installation of a dependency in bun installthat could occur in non-interactive environments like GitHub Actions.
Frontend dev-server bugfixes
- Fixed: a crash in --hotmode when using vim-like swapfiles that could occur when a file's imports are changed or removed.
- Fixed: a crash in the dev server with --hotenabled when deleting a file imported by multiple other files.
- Fixed: a crash in the file watcher on Windows that could occur when many files changed at once, such as when switching git branches. This was caused by an index-out-of-bounds error when the number of file system events exceeded an internal buffer.
- Fixed: a crash that could occur when a client aborts an HTTP request.
- Fixed: a potential performance bottleneck in the dev server by improving internal buffer management for path resolution.
- Fixed a bug where import.meta.urlwas incorrect in the browser when using Hot Module Replacement (HMR). It now correctly useswindow.location.origininstead ofbun://.
bun:test bugfixes
- Fixed: expect(...).toHaveBeenCalledWith()and related mock function matchers now show a colorful diff when assertions fail, making it much easier to debug tests with complex object arguments.
- Fixed: beforeAllhooks inbun testwould run fordescribeblocks that did not contain any tests matching the current test filter.
- Fixed: bug with expect(() => { throw undefined }).toThrow(ErrorClass)
- Fixed: jest.fn().mockRejectedValue()would cause an unhandled rejection if the mocked function was never called.
- Fixed: beforeAllhooks inbun testwould run fordescribeblocks even when all tests within that block were filtered out.
- Fixed: bun testwould not correctly filter tests when a directory name was passed as an argument.
- Fixed: bun testwould display the warning for a passingtest.failing()on the wrong line.
- Fixed: toIncludeRepeatedinbun:testchecked for at least the specified number of occurrences instead of the exact number, aligning Bun's behavior with Jest.
- Fixed: bun testwould fail when running multiple test files using thenode:testmodule.
Windows bugfixes
- Fixed: an assertion failure on Windows when resolving an invalid file path.
- Fixed: an integer cast panic when reading large files on Windows
Runtime bugfixes
- Fixed: terminal syntax highlighter that would incorrectly add an extra closing brace }to error messages involving template literals.
- Improved: Transfer-Encoding header validation with duplicate values. Thanks to Radman Siddiki for the report.
Bun.SQL
- Fixed: a crash in Bun.SQLthat could occur when a database connection fails.
- Fixed: an "index out of bounds" that could occur during large batch inserts.
- Fixed: a bug in Bun.sqlclient that could cause the process to hang indefinitely, particularly when queries were pending during shutdown.
File system and Bun.file
- Fixed: calling .write(),.writer(),.unlink(), or.delete()on a read-onlyBlob(one not created viaBun.file()) would not throw an error. It now correctly throws an error stating thatBlobs backed by bytes are read-only, matching the behavior ofBun.write().
Bun.which and executable resolution
- Fixed: Bun.whichon Windows failed to find executables in directory paths containing non-ASCII characters. This impacted lifecycle scripts in bun install as well.
Bun.resolve and module resolution
- Fixed: Bun.resolve()andBun.resolveSync()now consistently throwErrorobjects on failure. Previously, they could throw raw values, causing crashes intry...catchblocks.
Bun.s3
- Fixed a crash that could occur in Bun.s3.unlink()when S3 credentials were not configured.
Response constructor and Web APIs
- Fixed: string coercion of statusTextto theResponseconstructor
- Fixed: Response.redirect()will now correctly throw aRangeErrorwhen an invalid status code is provided.
Environment variables and configuration
- Fixed a bug where environment variables loaded from .envfiles would be truncated if they were longer than 4096 characters. This could also cause a crash.
Installation and platform-specific fixes
- Fixed a bug in the Windows install script (install.ps1) that incorrectly joined the local script'sPATHenvironment variable by joining paths with spaces instead of semicolons.
Memory management and performance
- Bun's threadpool now releases memory more aggressively after 10 seconds of inactivity, reducing memory usage during idle periods.
- Optimized an internal synchronization primitive, WaitGroup, by replacing mutex locks with atomic operations. This can improve performance in scenarios with a high number of concurrent tasks.
TypeScript type improvements
- Fixed: @types/bunis now compatible with TypeScript 5.9, resolving a type conflict withArrayBufferthat previously requiredskipLibCheck: trueintsconfig.json.
- In bun:sqlite, TypeScript types fordb.transaction()have been improved to correctly infer the return type from the transaction callback. This allows you to return data from within a transaction in a type-safe way. The arguments passed to the transaction are also correctly typed.