Bun v1.0.4

Jarred Sumner · October 3, 2023

Bun v1.0.4 fixes 62 bugs, adds server.requestIP, supports virtual modules in runtime plugins, and reduces memory consumption in Bun.serve(). Thank you for reporting issues. We are working hard to fix them as quickly as possible.

Bun is an incredibly fast JavaScript runtime, bundler, transpiler, and package manager — all in one. We've been releasing a lot of changes to Bun recently. Here's a recap of the last few releases. In case you missed it:

  • v1.0.0 - Bun's first stable release!
  • v1.0.1 - Named imports for .json & .toml files, bugfixes to bun install, node:path, Buffer
  • v1.0.2 - Make --watch faster, plus bug fixes
  • v1.0.3 - emitDecoratorMetadata, Nest.js support, private registry fixes, and many bugfixes

To install Bun:

curl -fsSL https://bun.sh/install | bash
npm install -g 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


Reduced memory usage in Bun.serve()

Bun.serve() now reports manually-managed per-request memory usage to JavaScriptCore's garbage collector. This reduces memory usage of Bun.serve() by 50% in some cases.

Implement server.requestIP()

With #6165, the IP address of a given Request can now be retrieved using server.requestIP().

  port: 3000,
  handler: (req, res) => {

This does not read headers like X-Forwarded-For or X-Real-IP. It simply returns the IP address of the socket, which may correspond to the IP address of a proxy.

We've also added support to node:http for getting the socket address. net.Socket().address now returns an object with address, port, and family properties.

Virtual modules in Bun.plugin

With #6167, Bun's plugin system gets more flexible and esbuild-compatible. It now supports fully virtual modules (import stuff from "foo"), in addition to custom loaders (import stuff from "./stuff.foo").

You can register a virtual module by registering a plugin.

import { plugin } from "bun";

  name: "my plugin",
  setup(builder) {
    builder.module("my-virtual-module", () => {
      return {
        exports: {
          hello: "world",
        loader: "object",

This virtual module can then be consumed like a normal module:

import { hello } from "my-virtual-module";
console.log(hello); // "world"

// require("my-virtual-module") also works
// await import("my-virtual-module") also works
// require.resolve("my-virtual-module") also works

This feature is currently only supported for runtime plugins, not bun build.

Support parameters in console.dir

Thanks to @liz3 for adding support for the second params object to console.dir() in #6059

console.dir({ 1: { 2: { 3: 3 } } }, { depth: 0, colors: false });

Potentially breaking changes

fetch() & bun install now have a network timeout of 5 minutes instead of 30 seconds

After a number of reports about fetch() & bun install timeout being too quick, we've increased the default timeout for fetch() from 30 seconds to 5 minutes. This aligns the default with Google Chrome and should help with high-latency connections. It also applies to bun install. Note that this timeout is not for the cumulative time of the request, but rather the time between each chunk of data received. If you want to disable the timeout entirely, you can pass timeout: false to fetch().

bun install now stores the package.json "version" field of workspace member packages in the lockfile

Previously, bun install would infer the package.json versions from other existing data when retrieved next, but this turned out to not work very well because you don't always need the package.json version of workspace member packages (they might not have one). The lockfile now stores the package.json version of workspace member packages, which helps address an issue where having a dependency using the npm version in the package.json but referencing the local workspace version would cause bun install to fail.

This is an incremental update to the existing lockfile in-place, it should have no impact other than a dirty git status the next time a lockfile which has workspace member packages with a version set. This is not technically a breaking change because this didn't work before, but it feels worth noting.

bun install bugfixes

Several stability improvements, including to workspaces, have been made to bun install:

  • Fix bun add <package> when run inside a workspace member package #6092
  • Fix bun install "forgetting" about the existence of a workspace after the initial install
  • Fixed a bug impacting Git/GitHub dependencies when the branch name contained a slash #5941.
  • Fix occasional hang in bun install #6192
  • Support local .tgz dependency #5812
  • Fix a determinism bug that could happen when saving a lockfile, causing git status to report a dirty working tree when nothing actually changed.

Major bugfixes

Fix a bug causing fetch to timeout in some cases with 3xx status codes

There was a bug where fetch would timeout in certain cases involving 3xx status codes and empty bodies when some headers were not included. The request would complete, but would eventually timeout instead of reporting success. This also impacted bun install in certain cases.

Fix captureStackTrace for subclasses of Error without super()

#6063 fixes a crash when using captureStackTrace inside a constructor without super() in extended classes.

class ExtendedError extends Error {
  constructor() {
    Error.captureStackTrace(this, ExtendedError);

class AnotherError extends ExtendedError {}

throw new AnotherError();

Fix a DNS resolution bug causing "Connection Refused" errors

Our usage of getaddrinfo was incorrect when the first returned result would fail to connect. getaddrinfo returns a linked list of results, but we were only looking at the first one. Now we look at all of them.

Implement isBinary in 'connection' callback for ws

Per #5944:

import WebSocket, { WebSocketServer } from "ws";

const wss = new WebSocketServer({
  port: 3000,

wss.on("connection", (ws) => {
  ws.on("message", (data, isBinary) => {
    // isBinary is now implemented
    console.log("received", data, isBinary);

Node.js compatibilitiy improvements

  • Several bugs impacting Next.js pages router have been fixed, thanks to @paperdave
  • util.inspect has been rewritten to be more compatible with Node.js, thanks to @jhmaster
  • A bug on macOS where fs.rm would not remove write-protected files has been fixed
  • A bug where the callback version of fs.exists would mistakenly include an error parameter has been fixed, thanks to @Hanaasagi


#5903fix(runtime): exclude unevaluated module in require.cache by @Hanaasagi
#5941[install] fix GitHub dependency bugs by @dylan-conway
#5944isBinary by @dylan-conway
#5986Fixes #5985 by @Jarred-Sumner
#5950Use c-ares function for checking if a string is an IP address by @Jarred-Sumner
#6000Correctly fix #5888 by @Jarred-Sumner
#6001Do not use removefileat() by @Jarred-Sumner
#6026fix latest dev build panic by @Hanaasagi
#6013Fix create command with template prefixed with @ char #6007 by @axlEscalada
#6030Add fs.statfs{Sync} to missing fs apis by @techvlad
#6032Make error message for new URL(invalid) better by @Jarred-Sumner
#5998Add Module._extensions by @Jarred-Sumner
#6036Drain microtasks at end of abort() if called into JS by @Jarred-Sumner
#6063fix captureStackTrace inside constructor without super in extended by @dylan-conway
#5771Improve Docker images by @Electroid
#6090fix: Docker - Include bunx symlink in distroless variant by @polarathene
#6086fix(fetch/server) fix server end of stream, fix fetch not streaming without content-length or chunked encoding, fix case when stream do not return a promise on pull by @cirospaciari
#6059fix: support console.dir options object correctly by @liz3
#6092fix workspace dependency install by @dylan-conway
#6097fix(node:fs): fix fs.exists callback parameters by @Hanaasagi
#6100fix: Docker - Apply workaround with RUN to symlink bunx by @polarathene
#5825fix: implement correct behaviour for urls with blob: scheme by @liz3
#6122fix(bun install): Handle vercel and github tarball path dependencies by @booniepepper
#6123revert fix for passing empty env vars to bun run by @dylan-conway
#5932deadCodeElimination toggle for Bun.Transpiler by @jhmaster2000
#6130fix typescript metadata for import identifiers by @dylan-conway
#4493Complete rework of the majority of node:util, primarily util.inspect by @jhmaster2000
#6095Get Next.js Pages Router to work by @paperdave
#6135Reduce memory usage of HTTP server by @Jarred-Sumner
#6118Add local tarball install #5812 by @axlEscalada
#6158Upgrade to latest Node.js version by @Jarred-Sumner
#6162Fixes #6053 by @Jarred-Sumner
#6165feat(runtime): implement server.requestIp + node:http socket.address() by @paperdave
#5766fix(resolver): support encoded file urls by @paperdave
#5945fix(runtime): Socket.prototype is undefined by @paperdave
#6154fix: don't set default request method when creating a Request from another by @liz3
#6185fix(runtime): followup for server.requestIP by @paperdave
#6167Implement virtual module support in Bun.plugin by @Jarred-Sumner
#6192Fix hang in bun install by @Jarred-Sumner
#6195tweak github actions by @Jarred-Sumner
#6206Fix bug causing "Connection Refused" errors by @Jarred-Sumner
#6207fix(node:process): fix return value of process.kill by @Hanaasagi
#6219Slightly reduce number of open file descriptors in bun install by @Jarred-Sumner
#6231Added the fileExtensions field to file-system-router.md by @cornedor
#6242Warn at start when using AVX build of Bun without AVX support by @Jarred-Sumner
#6247Fix bun install reading Github API from wrong environment variable by @Electroid
#6217Set fetch timeout to 5 minutes by @Jarred-Sumner

Thanks to Bun's newest contributors!

@meck93 @aszenz @cyfung1031 @axlEscalada @techvlad @Dawntraoz @polarathene @DarthDanAmesh @DevinJohw @cornedor @ciceropablo

Full Changelog: https://github.com/oven-sh/bun/compare/bun-v1.0.3...bun-v1.0.4