Bun v0.8.0 adds debugger support, implements fetch streaming, and unblocks SvelteKit. ReadStream and WriteStream from node:tty
are implemented, and .setRawMode()
now works on process.stdin
, unblocking several interactive CLI tools. Plus Node.js compatibility updates, bug fixes, stability improvements.
Bun 1.0 is coming on September 7th! Register for the launch stream at https://bun.sh/1.0.
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:
v0.7.0
- Web Workers,--smol
,structuredClone()
, WebSocket reliability improvements,node:tls
fixes, and more.v0.7.1
- ES Modules load 30-250% faster,fs.watch
fixes, and lots ofnode:fs
compatibility improvements.v0.7.2
- Implementsnode:worker_threads
,node:diagnostics_channel
, andBroadcastChannel
.v0.7.3
- Coverage reporting inbun test
, plus test filtering withbun test -t
.
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
Debugger support
Bun now implements debugger support via WebKit's Inspector Protocol. To use it, run your file or script with the --inspect
flag. Consider the following simple HTTP server.
const server = Bun.serve({
fetch(req){
console.log(req.url);
return new Response("Hello world!");
}
});
console.log(`Listening on http://localhost:${server.port}`);
When we run this file with --inspect
, it starts our HTTP server and spins up a localhost WebSocket server on an unused port. This WebSocket server uses the Inspector Protocol to communicate with debugging tools, which can introspect and control the running bun
process.
bun --inspect server.ts
Listening on http://localhost:3000
------------------ Bun Inspector ------------------
Listening at:
ws://localhost:6499/0tqxs9exrgrm
Inspect in browser:
https://debug.bun.sh/#localhost:6499/0tqxs9exrgrm
------------------ Bun Inspector ------------------
Using debug.bun.sh
The --inspect
flag will also print a https://debug.bun.sh#
URL to the console. This domain debug.bun.sh
hosts a stripped-down version of Safari Developer Tools designed for debugging Bun. Open the link in your preferred browser and a new debugging session will start automatically.
From the web debugger, you can inspect the currently running code and set breakpoints. Once a breakpoint is triggered, you can:
- View all variables in scope
- Execute code in the console, with full access to in-scope variables and Bun APIs
- Step through your code step-by-step
Read the Debug Bun with the web debugger guide for more complete documentation.
bun update
The new bun update
command will update all project dependencies to the latest versions that are compatible with the semver ranges in your package.json
.
bun update
To update a particular dependency:
bun update zod
Note — Unlike npm
, the bun upgrade
command is reserved for upgrading Bun itself. It is not an alias for bun update
.
Thanks to @alexlamsl for implementing this feature.
SvelteKit support
Improved support for environment variables in Worker
has unblocked SvelteKit. Scaffold your project with create-svelte
.
bunx create-svelte my-app
create-svelte version 5.0.5
┌ Welcome to SvelteKit!
│
◇ Which Svelte app template?
│ SvelteKit demo app
│
◇ Add type checking with TypeScript?
│ Yes, using TypeScript syntax
│
◇ Select additional options (use arrow keys/space bar)
│ none
│
└ Your project is ready!
✔ Typescript
Inside Svelte components, use <script lang="ts">
Install community-maintained integrations:
https://github.com/svelte-add/svelte-add
To install dependencies and start the dev server:
cd my-app
bun install
bun run dev -- --open
Open localhost:3000
to see the demo SvelteKit app in action.
Support for Nuxt (nuxt dev
)
With improved node:tty
and node:fs
support, the Nuxt development server now works with the Bun runtime. To get started, use the nuxi
command-line tool.
bunx --bun nuxi init my-app
cd my-app
bun install
Once dependencies are installed, start the development server with the "dev"
package.json script.
bun --bun run dev
$ nuxt dev
Nuxt 3.6.5 with Nitro 2.5.2
> Local: http://localhost:3000/
> Network: http://192.168.0.21:3000/
> Network: http://[fd8a:d31d:481c:4883:1c64:3d90:9f83:d8a2]:3000/
✔ Nuxt DevTools is enabled v0.8.0 (experimental)
ℹ Vite client warmed up in 547ms
✔ Nitro built in 244 ms
The --bun
flag ensures the server is using the Bun runtime instead of Node.js. By default the nuxt
CLI uses Node.js.
Then visit http://localhost:3000 to see the default Nuxt welcome screen.
Note — There are still some issues with Nuxt's build
command. When doing a production build, use bun run build
instead of bun --bun run build
. This will use Node.js to run Nuxt's build pipeline. Track this issue here.
Refer to the Building an app with Nuxt and Bun for a more complete walkthrough.
Fetch response body streaming
Bun now implements fetch()
response body streaming, thanks to @cirospaciari. This means that you can now stream data from a fetch response, instead of waiting for the entire response to be downloaded.
const res = await fetch("https://example.com/bigfile.txt");
// read the response chunk-by-chunk!
for await (const chunk of res.body) {
console.log(chunk);
}
Use OpenAI in Bun
Streaming is especially useful when working with APIs that take awhile to respond. Now you can stream responses from OpenAI's API in Bun.
import OpenAI from "openai";
const openai = new OpenAI({
apiKey: "my api key",
});
const stream = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: "Say this is a test" }],
stream: true,
});
for await (const part of stream) {
process.stdout.write(part.choices[0]?.delta?.content || "");
}
Bun.serve() streaming improvements
Previously, the following would buffer the response body, meaning it would only send the response once the entire body had been generated.
import { serve, sleep } from "bun";
serve({
fetch(req) {
return new Response(
new ReadableStream({
async pull(controller) {
for (let i = 0; i < 20; i++) {
controller.enqueue("Hello world!");
await sleep(42);
}
controller.close();
},
}),
);
},
});
// Hello World!Hello World!Hello World!...[~840ms]
That's not what people want! Now, the response body is streamed, meaning it's sent to the client as it's generated.
import { serve, sleep } from "bun";
serve({
fetch(req) {
return new Response(
new ReadableStream({
async pull(controller) {
for (let i = 0; i < 20; i++) {
controller.enqueue("Hello world!");
await sleep(42);
}
controller.close();
},
}),
);
},
});
// Hello world! [42ms]
// Hello world! [42ms]
// Hello world! [42ms]
Previously, streaming was only supported when using ReadableStream with type: "direct"
, a Bun-specific fast path for streaming.
import { serve, sleep } from "bun";
serve({
port: 3000,
fetch(req) {
return new Response(
new ReadableStream({
// bun specific option
type: "direct",
async pull(controller) {
for (let i = 0; i < 20; i++) {
controller.write("Hello world!");
// in bun < 0.8.0, flush() was required
controller.flush();
// now bun will automatically flush pending writes once the microtask queue is drained
await sleep(42);
}
controller.end();
},
}),
);
},
});
// Hello world! [42ms]
// Hello world! [42ms]
// Hello world! [42ms]
// Hello world! [42ms]
We still have optimization work ahead to make streaming using the default ReadableStream type fast. For now, we recommend using type: "direct"
to get the fastest possible streaming.
Support for node:tty
and process.stdin.setRawMode()
The ReadStream
and WriteStream
classes from node:tty
have been implemented, and process.stdin
is now an instance of ReadStream
. Accordingly, it's now possible to enable "raw mode" on process.stdin
.
process.stdin.setRawMode(true);
Support for inquirer
and other prompt libraries
This makes it possible to read keypresses without waiting for a newline character, which is important for interactive CLI tools. The popular libraries inquirer
, enquirer
, and prompts
are now fully supported.
Run the following command to interactively scaffold a Remix app using Bun and the interactive create-remix
command-line tool.
bunx --bun create-remix
Thanks to @dylan-conway for implementing this feature.
Improvements to bun test
test.each
and describe.each
Thanks to @jecquas, Bun now supports test.each
and describe.each
from Jest. This makes it easy to run the same test with different inputs.
describe.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])("add(%i, %i)", (a, b, expected) => {
test(`returns ${expected}`, () => {
expect(a + b).toBe(expected);
});
});
.toSatisfy()
and .toIncludeRepeated()
Thanks to @TiranexDev, bun test
now supports additional matchers. These matchers are part of jest-extended
and are now natively supported by bun test
.
Sample usage of .toSatisfy()
:
const isOdd = (value: number) => value % 2 !== 0;
it("toSatisfy", () => {
expect(1).toSatisfy(isOdd);
expect(2).not.toSatisfy(isOdd);
});
Sample usage of .toIncludeRepeated()
:
test("toIncludeRepeated", () => {
// check if string contains substring exactly 2 times
expect("hello hello").toIncludeRepeated("hello", 2);
// works with .not
expect("hello hello world").not.toIncludeRepeated("hello", 1);
});
40x faster buffer.toString("hex")
The Node.js Buffer.toString("hex")
function gets optimized with SIMD, leading to 40x faster performance.
In the next version of Bun
— Jarred Sumner (@jarredsumner) August 21, 2023
Buffer.toString("hex") gets 40x faster pic.twitter.com/Hz7rXBAjJw
Bun.inspect.custom
Objects can now be augmented with custom formatters using the Bun.inspect.custom
symbol. For compatibility reasons, util.inspect.custom
from Node.js's node:util
works too.
class Password {
value: string;
constructor(value: string) {
this.value = value;
}
[Bun.inspect.custom]() {
return "Password <********>";
}
}
const p = new Password("secret");
console.log(p);
// => "Password <********>"
Global File
constructor
The File
constructor has been added as a new global. File
instances can be constructed.
const file = new File(["hello world"], "hello.txt", {
type: "text/plain",
lastModified: Date.now() - 1000,
});
file.size; // 11
file.name; // "hello.txt"
file.type; // "text/plain"
file.lastModified; // 1693597759310573
Crash in Buffer-related functions fixed
A JIT crash in Buffer
-related functions has been fixed. This crash was caused by incorrect side effects when passed to DOMJIT which led to a crash during type validation when the functions were called. This impacted several libraries and the crash began after a JavaScriptCore upgrade in Bun v0.7.3.
This crash would cause EXC_BREAKPOINT
to be thrown after enough calls to Buffer.alloc
, Buffer.allocUnsafe
, Buffer.isBuffer
were called.
Bugfixes and stability improvements
Buffer.toString("hex") memory leak fix
A memory leak has been fixed in the implementation of buffer.toString("hex")
.
NAPI fixes and support for resvg
, sharp
A couple bugs in the NAPIClass
constructor and napi_create_external_arraybuffer
/ napi_create_external_buffer
have been fixed. The resolves issues when using resvg-js
or sharp
.
Better error when this
is invalid
When calling a method with an unexpected value for this
, Bun now reports an informative error.
const { json } = new Response(`"hello"`);
json();
// ^ TypeError: Expected `this` to be instanceof Response
Handle cross-device file copies
Bun now detects when a file copying operation (e.g fs.copyFile
) is attempting to copy files across devices or partitions and falls back to a manual file copy syscall.
Fix Bun.deepEqual
URL comparison
#4105
fixes a bug where URLs we're not properly compared by their internal href
.
10% Regression in async-await performance on macOS has been fixed
- The daylight savings time cache is no longer updated on each microtask call. This regression began in v0.7.x.
Several fixes to streams
#4251
includes a number of improvements and bugfixes in the implementation of ReadableStream
have been fixed. This includes:
- Pending writes to HTTP response bodies are automatically flushed once the microtask queue has been drained, fixing #1886
- Improved error handling inside
pull
.
Changelog
As Bun 1.0 approaches, we've been tracking down remaining memory leaks and crashes.
#4028 | [install] Handle bun add of existing peerDependencies correctly by @alexlamsl |
#4026 | Running missing scripts exits with non-0 by @YashoSharma |
#4030 | Bind require.resolve`() by @Jarred-Sumner |
#4034 | Normalize Request URLs by @Jarred-Sumner |
#4042 | Fix path.normalize edge case. by @Hanaasagi |
#4043 | Compile Bun's transpiler to WASM and add test analyzer by @Jarred-Sumner |
#4048 | Fix iterating headers with set-cookie by @dylan-conway |
#4000 | implement fetching data urls by @dylan-conway |
#4054 | Fix Bun.hash functions by @jhmaster2000 |
#4064 | Fix path.format compatibility issue. by @Hanaasagi |
#4073 | Fix require("console") #3820 by @paperdave |
#4076 | Set exports to {} in user-constructed CommonJSModuleRecords by @paperdave |
#4086 | Fix XLSX.read coredump by @Hanaasagi |
#4027 | Add support for bun --revision by @YashoSharma |
#4106 | Fix segfault in base64url encoder #4062 by @Jarred-Sumner |
#4109 | Handle thundering herd of setInterval by @Jarred-Sumner |
#4111 | Fix memory leak in Buffer.toString('base64url') by @Jarred-Sumner |
#4113 | Run files without extensions by @dylan-conway |
#4117 | Make astro build slightly faster |
#4125 | Support TypeScript's export type * as Foo from 'bar' by @Jarred-Sumner |
#4126 | bun-wasm fixes & improvements by @jhmaster2000 |
#4131 | Deprecate loading node_modules.bun by @Jarred-Sumner |
#4129 | Fix custom config path not working. by @Hanaasagi |
#4114 | Fix worker event loop ref/unref + leak by @paperdave |
#4152 | Make builtins' source origin use a valid url by @paperdave |
#4155 | Fix importing too long of strings by @paperdave |
#4162 | Fix method name typo by @Hanaasagi |
#4157 | Fix event loop issue with Bun.connect by @paperdave |
#4172 | Update docs our current status of node compatibility by @paperdave in https://github.com/oven-sh/bun/pull/4172 |
#4173 | Create domjit.test.ts by @dylan-conway in https://github.com/oven-sh/bun/pull/4173 |
#4150 | Fix prisma linux generation by @cirospaciari in https://github.com/oven-sh/bun/pull/4150 |
#4181 | Fix leaking .ptr by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4181 |
#4192 | correct guide's bunfig example option by @xxxhussein in https://github.com/oven-sh/bun/pull/4192 |
#4193 | refactor: move HTMLRewriter to c++ bindings by @bru02 in https://github.com/oven-sh/bun/pull/4193 |
#4191 | Fix(node:fs): add buffer parameter in fs.read callback. by @Hanaasagi in https://github.com/oven-sh/bun/pull/4191 |
#4154 | Allow IncomingRequest.req to be overwritten. by @paperdave in https://github.com/oven-sh/bun/pull/4154 |
#4098 | Support Nitro by @paperdave in https://github.com/oven-sh/bun/pull/4098 |
#4194 | Add util.inspect.custom support to util.inspect/Bun.inspect/console.log by @paperdave in https://github.com/oven-sh/bun/pull/4194 |
#4187 | Remove most C API usages, add debugger pretty printers for Headers , URLSearchParams , FormData , Worker , EventTarget by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4187 |
#4208 | Implement BigIntStats by @paperdave in https://github.com/oven-sh/bun/pull/4208 |
#4206 | feat: add self-closing & can-have-content by @bru02 in https://github.com/oven-sh/bun/pull/4206 |
#4213 | Add inline sourcemaps when --inspect is enabled by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4213 |
#4220 | Fixes #172 by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4220 |
#4221 | Fix crash impacting sharp & resvg by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4221 |
#4210 | Add unsupported (yet) comment to distroless image by @o-az in https://github.com/oven-sh/bun/pull/4210 |
#4163 | Fix(bundler): use different alias mappings based on the target. by @Hanaasagi in https://github.com/oven-sh/bun/pull/4163 |
#4231 | Fix test failures from 3a9a6c63a by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4231 |
#4222 | Implement --inspect-brk by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4222 |
#4230 | Fixes #1675 by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4230 |
#4235 | Fix memory leak in buffer.toString("hex") by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4235 |
#4237 | Buffer.toString('hex') gets 40x faster by @Jarred-Sumner in https://github.com/oven-sh/bun/pull/4237 |
#4243 | feat: Implement Bun.inspect.custom by @paperdave |
#4156 | Implement napi_ref_threadsafe_function by @paperdave |
#4242 | Fix crypto.EC constructor by @paperdave |
#4226 | Fix(bundler): allow generating exe file in nested path. by @Hanaasagi |
#4245 | Fix emitKeyPresses with backspace + quote by @paperdave |
#4127 | fetch(stream) add stream support for compressed and uncompressed data by @cirospaciari |
#4244 | import errors have code set to ERR_MODULE_NOT_FOUND and require errors have code set to MODULE_NOT_FOUND by @Jarred-Sumner |
#4250 | fix stdin stream unref and resuming by @dylan-conway |
#4247 | fix fsevents and stub for qwikcity by @paperdave |
#4264 | fix(parser): yield before ] shouldn't be a syntax error by @paperdave |
#4256 | Ask for bun --revision instead bun -v in PR template by @xHyroM |
#4273 | Fix more types. by @xxxhussein |
#4251 | Bunch of streams fixes by @Jarred-Sumner |