This release fixes 50 issues (addressing 80 👍), and adds +24 passing Node.js tests. Ahead-of-time bundling for HTML imports, more reliable Bun Shell, setTimeout
and setImmediate
use 8-15% less memory, columnTypes
& declaredTypes
in bun:sqlite
, bun info
is the new bun pm view
, Node.js compatibility improvements to child_process.fork
, fs.glob
options are now optional, tls.getCACertificates()
is now implemented, bun init
generates CLAUDE.md
when claude code is installed, and more.
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
Ahead-of-time bundling for HTML imports
HTML imports in Bun now support ahead of time bundling in server-side code.
That means you can now use bun build
to bundle a full-stack application by importing an .html
file directly into your server-side code. Bun will parse the HTML, bundle any referenced client-side JavaScript (<script src>
) and CSS (<link rel="stylesheet">
), and automatically configure the server to serve all the bundled assets.
This eliminates runtime bundling overhead in production. When combined with the --compile
flag, you can create a single, self-contained executable for your entire application, frontend and backend included. The development workflow remains unchanged; running your server with bun --hot
will still provide on-demand bundling and Hot Module Replacement.
import { serve } from "bun";
import homePage from "./index.html";
// This server will serve the HTML file and all its bundled assets.
serve({
routes: {
"/": homePage,
},
});
<!DOCTYPE html>
<html>
<head>
<title>My Full-Stack App</title>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<h1>Hello, Bun!</h1>
<script src="./client.ts" type="module"></script>
</body>
</html>
console.log("Hello from the client-side script!");
body {
background-color: #f0f0f0;
}
To create a full-stack production build, run bun build
with the --target=bun
flag.
bun build ./src/server.ts --target=bun --outdir ./dist
To create a full-stack self-contained executable, run bun build
with the --compile
flag.
bun build ./src/server.ts --compile --outfile=my-app
# Run via ./my-app
Previously, HTML imports were only supported at either runtime or as entry points. You couldn't mix server-side and client-side code in the same build. You had to do it at runtime. Now you can do it at build time.
And also, it's fast.
Full-stack React app compiled with bun build --compile serves the same index.html file 1.8x faster than nginx https://t.co/tPU3KdHzjU pic.twitter.com/XQhJPlaqxP
— Jarred Sumner (@jarredsumner) June 20, 2025
Bun Shell reliability improvements
Bun's cross-platform bash-like shell, Bun.$
, no longer uses the native call stack for execution, preventing stack overflow errors in deeply-nested or complex shell scripts. This was a large refactor of the shell's internals.
Thanks to @zackradisic for the contribution
setTimeout
and setImmediate
use 8-15% less memory
An internal optimization to how Bun manages Strong references to JavaScript values from native code reduced the memory footprint for each setTimeout
and setImmediate
call. By removing a layer of pointer indirection, Bun now uses 8% to 15% less RAM for each timer, improving performance in applications with many concurrent timers.
// Each of these timers now consumes less memory.
for (let i = 0; i < 10000; i++) {
setTimeout(() => {
// ...
}, 1000);
}
columnTypes
& declaredTypes
in bun:sqlite
The Statement
object in bun:sqlite
now has two new properties for introspecting column types: declaredTypes
and columnTypes
.
stmt.declaredTypes
returns an array of type strings as defined in your CREATE TABLE
schema. For expressions or computed columns not backed by the schema, the value in the array will be null
.
stmt.columnTypes
returns an array of type strings based on the actual values in the first row of the result set. This is particularly useful for determining the type of computed columns. These additions are a key step toward enabling a Prisma driver adapter for bun:sqlite
.
import { Database } from "bun:sqlite";
const db = new Database(":memory:");
db.run("CREATE TABLE users (id INTEGER, name TEXT)");
db.run("INSERT INTO users (id, name) VALUES (1, 'Alice')");
const stmt = db.query("SELECT id, name FROM users LIMIT 1");
// .get() must be called to populate the statement before accessing these properties
stmt.get();
// Types from the `CREATE TABLE` schema
// Note: `
console.log(stmt.declaredTypes);
// => ["INTEGER", "TEXT"]
// Types from the actual values in the first row
console.log(stmt.columnTypes);
// => ["INTEGER", "TEXT"]
Thanks to @crishoj for the contribution!
bun info
is the new bun pm view
The bun pm view
command has been renamed to the more intuitive bun info
, which was reserved for this usecase originally. This command fetches and displays package metadata from the npm registry, such as its description, versions, and dependencies. The previous bun pm view
command is preserved as an alias for backward compatibility.
You can also query for specific top-level or nested fields in a package's package.json
.
// View basic package information
$ bun info react
react@18.2.0 | MIT | 3 dependencies
React is a JavaScript library for building user interfaces.
https://react.dev/
// Get a specific field, like the latest version
$ bun info react version
// "18.2.0"
// Get a nested field
$ bun info react repository.url
// "git+https://github.com/facebook/react.git"
// The old command still works as an alias
$ bun pm view react
bun init
+ Claude Code
When you run bun init
, Bun will now automatically generate a CLAUDE.md
file if the claude
CLI tool is detected in your PATH
. This file provides contextual instructions to AI coding assistants like Anthropic's Claude, which helps improve the quality of its suggestions for your project.
If you also use the Cursor editor, bun init
will intelligently create a CLAUDE.md
file and symlink Cursor's rule file (.cursor/rules/
) to it. This helps keep your AI instructions consistent across different tools.
You can disable this behavior by setting the BUN_AGENT_RULE_DISABLED
or CLAUDE_CODE_AGENT_RULE_DISABLED
environment variables.
Node.js compatibility improvements
child_process.fork()
now supports execArgv
The execArgv
option in child_process.fork()
is now correctly implemented, improving Node.js compatibility. This allows you to pass command-line arguments to the forked Bun process. Previously, this option was ignored.
Additionally, the Node.js-specific process._eval
property is now supported. It contains the code string when Bun is run with the -e
or --eval
flags.
// parent.js
import { fork } from "child_process";
// Fork a new Bun process. The first argument is the module path.
// The `execArgv` option passes arguments to the new `bun` process.
const child = fork("./child.js", {
execArgv: ["--smol", "--hot"],
});
child.on("message", (message) => {
console.log("Message from child:", message);
// => Message from child: [ '--smol', '--hot' ]
});
// child.js
// The child process receives the arguments in `process.execArgv`.
process.send(process.execArgv);
Thanks to @riskymh for the contribution
Zstandard (zstd) support in node:zlib
Bun's built-in node:zlib
module now supports Zstandard (zstd) compression and decompression. This includes the synchronous, asynchronous, and streaming APIs. Zstandard is a fast lossless compression algorithm, providing high compression ratios.
Thanks to @nektro for the contribution
fs.glob
options are now optional
The options
argument for fs.glob
, fs.promises.glob
, and fs.globSync
is now optional, aligning Bun's behavior with Node.js. Previously, an error would be thrown if the options
argument was omitted.
import { globSync } from "node:fs";
// This previously threw an error in Bun.
// It now works, just like in Node.js.
const files = globSync("*.js");
console.log(files);
Thanks to @riskymh for the contribution
tls.getCACertificates()
is now implemented
The tls.getCACertificates()
function from Node.js is now implemented in Bun. It returns an array of trusted root CA certificates in PEM format that are bundled with Bun.
This is useful for inspecting the root certificates Bun uses for establishing secure TLS connections. Note that loading system-wide CA certificates is not yet supported.
import { getCACertificates } from "node:tls";
const certs = getCACertificates();
// Logs the number of bundled CA certificates
console.log(`Loaded ${certs.length} CA certificates.`);
// Each element is a certificate in PEM format
console.log(certs[0]);
// -----BEGIN CERTIFICATE-----
// MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJVUzEX
// ...
// -----END CERTIFICATE-----
Thanks to @pfgithub for the contribution
Customize unhandled promise rejection behavior with --unhandled-rejections
Bun now supports the Node.js-compatible --unhandled-rejections
command-line flag. This allows you to configure how the runtime handles promises that are rejected without a .catch()
handler, providing finer-grained control for debugging and improving compatibility with Node.js applications.
The following modes are supported:
throw
: Raise an uncaught exception, immediately terminating the process.strict
: Raise an uncaught exception. If the promise is handled later, therejectionHandled
event is emitted onprocess
, but the process will still exit with a non-zero code.warn
: Print a warning to stderr but allow the process to continue execution. This is the default in modern Node.js.none
: Silently ignore unhandled rejections.
Bun's default behavior remains unchanged. As part of this change, the process.on('rejectionHandled', ...)
event is now also supported.
// file: unhandled.js
const promise = Promise.reject(new Error("Something went wrong!"));
// Run this file with different flags to observe the behavior.
// Throws an exception and exits with a non-zero exit code.
// $ bun --unhandled-rejections=throw unhandled.js
// error: Uncaught Error: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Error: Something went wrong!".
// ...
// Prints a warning and continues execution.
// $ bun --unhandled-rejections=warn unhandled.js
// (bun:87363) UnhandledPromiseRejectionWarning: Error: Something went wrong!
// at unhandled.js:2:23
// (Use `bun --trace-warnings ...` to show where the warning was created)
// (bun:87363) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=throw` or `process.on('unhandledRejection', (err) => { throw err; })`. (rejection id: 1)
// Exits silently with a zero exit code.
// $ bun --unhandled-rejections=none unhandled.js
Thanks to @pfgithub for the contribution
JavaScriptCore upgrade
This release also upgrades JavaScriptCore, bringing several performance improvements thanks to the JavaScriptCore team.
String Operations
- Patterns like
str += str
now generate more efficient code in the JIT compiler String.prototype.charCodeAt()
andcharAt()
are now folded at JIT compile-time when both the string and index are constants, eliminating runtime operations.- String type tracking improvements: JavaScriptCore's DFG JIT now tracks rope strings vs resolved strings, enabling more aggressive optimizations and avoiding unnecessary string resolution checks.
- Patterns like
obj["prefix" + variable]
get special treatment in the JIT compiler, where one part of the string concatenation is constant.
Array Operations
- Fast path for
[Symbol.toPrimitive]("Array")
Array.prototype.toReversed()
optimization: Improved performance when reversing arrays that contain holes by using more efficient algorithms.
Number and Math Operations
Number.isSafeInteger
is now JIT compiled, which makes it about 16% faster in microbenchmarksMath.sumPrecise
implements Radford M. Neal's xsum algorithm with a large superaccumulator for arrays with more than 1,000 elements, which is 10% faster on large datasetsMath.hypot
avoids unnecessary vector allocation when called with no arguments
JSON Stringification
- Zero-copy JSON stringifier: The fast JSON stringifier now adopts dynamically allocated buffers directly without copying when converting to strings, eliminating memory allocation and copying for large JSON strings.
Optimizer improvements
- The integer range optimizer now handles
CheckInBounds
operations with constant bounds and provides range analysis forArithBitAnd
operations with constant masks, enabling elimination of more runtime bounds checks. - Megamorphic inline cache for
in
operator now uses a threshold-based approach
Security Hardening
- Eliminated semi-pinned register vulnerability in JavaScriptCore's WebAssembly In-Place Interpreter by removing the instruction base register and using dynamic base address calculation.
- Added proper bounds checking for SIMD prefix opcodes.
- Added additional security checks to ensure SIMD opcodes are always less than 0x100.
Bugfixes
Package manager bugfixes:
bun audit
now respects proxy settings viaHTTP_PROXY
andHTTPS_PROXY
environment variables- A potential infinite loop when installing packages in projects with a very large number of dependencies has been fixed
Parser bugfixes:
- TypeScript non-null assertions with the
new
operator:new obj!.a()
work as expected - Nested objects in macros that contain numeric property keys now work as expected
require.main === module
with--target=node
was incorrectly rewritten torequire.main === require.module
. Now it's preserved as expected.
Bundler bugfixes:
bun build --compile
is slightly smarter about picking a default output filename. Previously, if the input file was namedindex
, it would pick the directory name as the output filename, which meant./src/index.ts
would attempt to save to./src
, which was a directory and not a file - leading it to fail. Now it will detect that the path was a directory and will save to./src/index
(without the extension) instead.- A missing
async
in function declarations when top-level await is present in circular dependencies has been fixed - A regression from Bun v1.2.16 causing the displayed output filename in the embedded
--compile
binary to be incorrect has been fixed
Runtime bugfixes:
- Fixed a rare crash in
Bun.spawn
- Fixed a crash in
bun:ffi
with pointers encoded as 32 bit integers - Several missing JavaScript exception checks in native code have been added, along with an automated way of detecting missing exception checks to prevent regressions in the future
- Strong references to native values avoid extra memory allocations
Misc:
- Windows icon is now properly set in the executable
bunx
now works on Windows when installed withnpm
bun init --react=tailwind
now logs the server URL to the console when the development server starts- A console warning in Bun's runtime error page has been fixed