Bun v1.1.27 is here! This release fixes 130 bugs (addressing 250 👍). bun pm pack, faster node:zlib. Static routes in Bun.serve(). ReadableStream support in response.clone() & request.clone(). Per-request timeouts. Cancel method in ReadableStream is called. bun run handles CTRL + C better. Faster buffered streams. bun outdated package filtering. Watch arbtirary file types in --hot and --watch. Fixes to proxies on Windows. Several Node.js compatibility improvements.
We're hiring systems engineers in San Francisco to build the future of JavaScript!
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 upgradeNative node:zlib
We rewrote node:zlib to use native code.
| Runtime | node:zlib | Stream (MB/s) | Sync (MB/s) |
|---|---|---|---|
| Bun v1.1.27 | deflate | 32.79 MB/s | 14.82 MB/s |
| Node v22.5.1 | deflate | 15.50 MB/s | 31.39 MB/s |
| Bun v1.1.26 | deflate | 15.59 MB/s | 10.29 MB/s |
| Bun v1.1.27 | deflateRaw | 32.68 MB/s | 14.60 MB/s |
| Node v22.5.1 | deflateRaw | 19.77 MB/s | 31.41 MB/s |
| Bun v1.1.26 | deflateRaw | 15.67 MB/s | 10.38 MB/s |
| Bun v1.1.27 | gunzip | 87.72 MB/s | 107.60 MB/s |
| Bun v1.1.26 | gunzip | 46.49 MB/s | 42.74 MB/s |
| Node v22.5.1 | gunzip | 31.01 MB/s | 75.86 MB/s |
| Bun v1.1.27 | gzip | 32.69 MB/s | 14.91 MB/s |
| Node v22.5.1 | gzip | 18.46 MB/s | 31.10 MB/s |
| Bun v1.1.26 | gzip | 15.29 MB/s | 10.11 MB/s |
| Bun v1.1.27 | inflate | 87.79 MB/s | 102.86 MB/s |
| Bun v1.1.26 | inflate | 50.72 MB/s | 43.83 MB/s |
| Node v22.5.1 | inflate | 26.07 MB/s | 74.64 MB/s |
| Bun v1.1.27 | inflateRaw | 87.68 MB/s | 101.78 MB/s |
| Bun v1.1.26 | inflateRaw | 53.89 MB/s | 43.13 MB/s |
| Node v22.5.1 | inflateRaw | 33.35 MB/s | 75.02 MB/s |
Via a third-party zlib benchmark on a Linux x64 Hetzner server.
There's still more to do to optimize node:zlib in Bun, but this is a good start.
Big thanks to @nektro for implementing this.
New command: bun pm pack
In the next version of Bun
— Bun (@bunjavascript) September 7, 2024
bun pm pack creates an npm package tarball for publishing or installing locally pic.twitter.com/RdXdyzI3He
bun pm pack is designed to be a drop-in replacement for npm pack.
New in Bun.serve() (HTTP server)
This release introduces reliability and quality of life improvements to Bun.serve(), our fast HTTP server.
Static routes
You can now pass a static option to serve static Response objects for a path.
Bun.serve({
static: {
"/api/health-check": new Response("🟢"),
"/old-link": Response.redirect("/new-link", 301),
"/api/version": Response.json(
{
app: require("./package.json").version,
bun: Bun.version,
},
{
headers: {
"X-Powered-By": "bun",
},
},
),
},
async fetch(req) {
return new Response("Dynamic!");
},
});
ReadableStream support in request.clone() and response.clone()
Cloning a streaming Request or Response is now supported via request.clone() and response.clone().
To clone a request from Bun.serve:
Bun.serve({
async fetch(req, server) {
const cloned = req.clone();
await req.json();
// Previously, this would be empty.
await cloned.json();
// ... rest of the code
},
});
To clone a Response from fetch:
const response = await fetch("https://example.com");
const cloned = response.clone();
console.log(await response.text());
console.log(await cloned.text());
Previously, this was only supported for static responses like when passing a string, an ArrayBuffer, or a Blob to the Response constructor.
The "cancel" method in ReadableStream
When a request is aborted, Bun now calls the cancel method in ReadableStream .
import { serve } from "bun";
serve({
async fetch(req, server) {
req.signal.addEventListener("abort", () => {
// Previously, AbortSignal was the only way to detect if a request was aborted.
console.log("Request aborted");
});
return new Response(
new ReadableStream({
async pull(controller) {
controller.enqueue("Hello World");
await Bun.sleep(1000);
},
cancel() {
// New! Called when the request is aborted.
console.log("Stream cancelled");
},
}),
);
},
});
Per-request timeouts
The new server.timeout(request: Request, seconds: number) method allows you to set a timeout per specific HTTP request.
To set a 60 second timeout for a request:
Bun.serve({
async fetch(req, server) {
server.timeout(req, 60); // 60 seconds
await req.formData();
return new Response("Slow response");
},
});
Thanks to @cirospaciari for implementing this.
Faster buffered streams
We didn't just add new features to Bun.serve() this release. We also made it faster.
In the next version of Bun
— Jarred Sumner (@jarredsumner) September 3, 2024
The fast path in request.json() & similar methods now works after accessing “.body”
New: 65,000 req/s
Prev: 29,000 req/s pic.twitter.com/2EqYyCoq4G
New CLI flag: --max-http-header-size
Passing --max-http-header-size sets the size of the HTTP request header buffer.
https://github.com/oven-sh/bun/pull/13577
Fixed: server.requestIP after await
Previously, using server.requestIP after a callback or call to await would lose the request metadata. This has been fixed.
Bun.serve({
port: 3000,
async fetch(req, server) {
console.log(server.requestIP(req));
// { address: '127.0.0.1', family: 'IPv4', ... }
await req.formData();
console.log(server.requestIP(req));
// now: { address: '127.0.0.1', family: 'IPv4', ... }
// before: undefined
},
});
Fixed: ws.publish on a closed WebSocket
In Bun.serve, calling .publish on a websocket will send a message to all clients except the websocket itself. When using this in the close handler, the WebSocket was already closed and no message could be sent. This has now been fixed.
Thanks to @cirospaciari for fixing this.
Fixed: memory leak when accessing request body and buffered methods
A memory leak has been fixed in code like the below:
Bun.serve({
async fetch(req) {
if (req.body) {
await req.json();
}
// ... rest of the code
},
});
When the Request body's ReadableStream was accessed, in certain cases a buffering method like req.json may use a different implementation and the Request object was incorrectly holding a strong reference to the Promise returned by req.json in those cases, leaking memory.
While adding clone() support for streams, we revised the implementation of Request and Response to fix this and similar issues.
bun outdated filtering
bun outdated now has --filter, which allows you to choose which workspaces you want to audit for outdated packages.
# Path patterns:
# Matches all workspaces in `./packages`bun outdated --filter="./packages/*"
# Name patterns:
# All workspaces with names starting with `pkg`bun outdated --filter="pkg*"
# All workspaces excluding `pkg1`bun outdated --filter="*" --filter="!pkg1"Additionally, positional arguments filter the list of dependencies, which can be helpful if you only want to check certain packages for updates.
# All dependencies starting with `is-` (could display `is-even`, `is-odd`, ...)bun outdated "is-*"
# All dependencies from a particular scopebun outdated "@discordjs/*"
# With `--filter`. Matches all outdated `jquery` dependencies in all workspaces.bun outdated jquery --filter="*"bun run Ctrl + C behavior is fixed
bun run wasn't propagating POSIX signals from the bun process to the child process (only from child -> parent). This led to strange bugs in certain cases, like CTRL + C not exiting the child process until later when an I/O error occurs from reading stdin on a disconnected terminal. This visually manifested as the ^[[A character appearing when you press ↑ Up instead of the previous command.
This has been fixed.
In the next version of Bun
— Jarred Sumner (@jarredsumner) September 6, 2024
A bug where the following would sometimes print ^[[A is fixed
1. bun run <package.json script>
2. Ctrl + C
3. ↑ Up pic.twitter.com/7YlR2knMLh
Thanks to @xales for debugging this.
Watch arbitrary file types in --watch and --hot
Bun's builtin watch & hot reloading now supports watching arbitrary file types.
To watch a file, import it.
import "./tailwind.css";
// ... rest of my app
Bun's watcher relies on the module graph to determine which files trigger a reload. This reduces unnecessary reloads, improving your iteration cycle time.
Previously, only JavaScript, TypeScript, JSON, TOML and .txt files were watched. Now, Bun will watch any file that is imported regardless of file extension.
Fixed: Default idleTimeout no longer set in node:http
In Bun 1.1.26, the default idleTimeout was 10 seconds, which was a breaking change as versions before had unlimited timeout. The default value of idleTimeout is now 0, which disables the timeout.
Node.js compatibility improvements
This release also includes a number of Node.js compatibility improvements.
Fixed: Crash while throwing an exception from N-API
A bug causing a crash in N-API when an exception was thrown has been fixed.
Fixed: Crash in N-API when accessing heap-allocated JSValue
JavaScriptCore & V8 are different engines with different approaches to garbage collection. JavaScriptCore scans the stack. V8 relies on handle scopes.
Previously, Bun didn't implement handle scopes. This led to crashes in N-API packages like DuckDB that heap-allocate napi values without referencing them in stack memory. The garbage collector wouldn't see them, and clean up the memory prematurely.
Thanks to @190n for implementing handle scopes.
Fixed: Crash impacting Next.js middleware
A crash in node:vm when using a class extending a built-in class like URL or Response inside of node:vm has been fixed. This crash was reproducible in Next.js middleware.
Fixed: Missing ERR_INVALID_ARG_TYPE in some Buffer methods
In Buffer.isAscii and Buffer.isUtf8, the error thrown when given invalid arguments now properly includes code: "ERR_INVALID_ARG_TYPE".
Fixed: Missing ERR_INVALID_URL in new URL
To match Node.js, the error thrown by new URL when giving an invalid URL now includes code: "ERR_INVALID_URL"
Fixed: AES-GCM encryption of empty messages
Thanks to @wpaulino, an empty message now properly round-trips in AES-GCM encryption.
Fixed: util.promisify with crypto.generateKeyPair
Thanks to @wpaulino, calling util.promisify on crypto.generateKeyPair will now return the proper promisified function.
Fixed: Handling out-of-memory errors in Buffer
When converting a large string to a Buffer, Bun now handles out-of-memory errors by throwing an OutOfMemoryError instead of crashing.
Fixed: node:tls accepting an arbitrary stream for a TLS socket. Fixed mssql package
The tls.connect function from node:tls accepts a socket option. This lets you upgrade any net.Socket to TLS. However, this parameter can actually be any arbitrary stream.Duplex, which Bun previously did not support, as it relies the underlying network connection to engage in TLS more efficiently.
This resolves the mssql package throwing Error: socket must be an instance of net.Socket when used.
Thanks to @cirospaciari
Fixed: node:http agent ignored
In certain cases, the node:http agent was not being used. This has been fixed.
Thanks to @nektro
Fixed: node:http setTimeout & server.setTimeout ignored
With server.timeout now implemented, we've also added support for server.setTimeout and request.setTimeout in node:http.
Thanks to @cirospaciari for fixing this.
Fixed: node:vm inconsistencies
Various subtle mistakes in node:vm have been fixed:
vm.runInThisContextnow operates in global contextscript.runInNewContextnow operates in it's own contextscript.runInThisContextandvm.runInThisContextdon't take context as an argumentvm.runInThisContext,vm.runInContext, andvm.runInContexttake a string as the options argument.
Thanks to @SunsetTechuila for fixing these!
Fixed: Missing net.Socket.destroySoon
Previously, this method in node:net was undefined. This is now fixed.
fetch reliability improvements
Proxies in fetch() on Windows work better now
On Windows, using a proxy with fetch often led to error: Syscall being thrown.
This has been resolved thanks to @cirospaciari.
Fixed: a memory leak with FormData or URLSearchParams body
In Bun v1.1.25, a regression was introduced where sending FormData and URLSearchParams in the body of a fetch() request would leak memory. This regression is now fixed.
Lots more fixes
Fixed: Reading large files Bun.file was truncated
When reading a file over 4gb into a single ArrayBuffer, the buffer would be truncated to 4gb. This has now been fixed.
Fixed: Clearing screen in some terminals
The ANSI escape code used to clear the terminal screen has been changed from \x1b[H\x1b[2J to \x1B[2J\x1B[3J\x1B[H, which is compatible with more terminals. Most notably, this fixes Visual Studio Code's terminal, which did not fully clear before this change.
Thanks to @jakebailey for fixing this.
Fixed: Handling out-of-memory errors in Bun.escapeHTML
When giving large enough strings to Bun.escapeHTML, it will now throw an OutOfMemoryError instead of crashing.
Bun.deepEquals performance improvements for Map and Set
After a the WebKit upgrade for Bun v1.1.19, the implementation of Map and Set changed to the point we had to remove their fast paths in Bun.deepEquals. Thanks to @wpaulino, a new fast path has been added, which is better than what was previously in place.
Additionally, the fast path covers custom classes that extend Map or Set, giving them nearly indistinguishable performance in Bun.deepEquals from the base class itself.
Fixed: Failed to link package: EBUSY on Windows
In bun install, an issue updating package binaries while they are currently open has been fixed
Thanks to @dylan-conway
Fixed: LCOV reporter properly reports non-hit lines
Bun's LCOV reporter previously would sometimes report 100% line coverage when that wasnt always the case. This has now been fixed thanks to @fmorency.
Fixed: bun add -g postinstall message
When installing a global package with a blocked postinstall script, the message will now include the correct command:
$ bun install -g @delance/runtime
bun add v1.1.27
installed @delance/runtime@2024.8.103 with binaries:
- delance-langserver
68 packages installed [1.98s]
-Blocked 1 postinstall. Run `bun pm untrusted` for details.
+Blocked 1 postinstall. Run `bun pm -g untrusted` for details.
Thanks to @RiskyMH for fixing this
Fixed: Race condition in Bun.build
A race condition causing a Bun.build promise to hang has been fixed. This could be caused if you queued many Bun.build calls in a short period of time.
Fixed: bun shell not keeping parent process alive
A bug where the following code would exit prematurely, wtihout printing "never reached!!! why!!" has been fixed.
import { $ } from "bun";
console.log("before shell");
(async function () {
await `echo hi`;
console.log("never reached!!! why!!");
})();