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 | 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
Native 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 scope
bun 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.runInThisContext
now operates in global contextscript.runInNewContext
now operates in it's own contextscript.runInThisContext
andvm.runInThisContext
don't take context as an argumentvm.runInThisContext
,vm.runInContext
, andvm.runInContext
take 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!!");
})();