Releases: oven-sh/bun
Bun v0.1.2
To upgrade:
bun upgrade
If you have any problems upgrading
Run this:
curl https://bun.sh/install | bash
What's Changed
bun install:
- Fix
error: NotSameFileSystem
- When the Linux kernel version doesn't support io_uring, print instructions for upgrading to the latest Linux kernel on Windows Subsystem for Linux
bun.js:
- Export
randomUUID
incrypto
module by @WebReflection in https://github.com/Jarred-Sumner/bun/pull/254 napi_get_version
should return the Node-API version by @kjvalencik in https://github.com/Jarred-Sumner/bun/pull/392
bun dev:
- Fix crash on running
bun dev
on linux on some machines (@egoarka) https://github.com/Jarred-Sumner/bun/pull/316
Examples:
- Minor updates to the Next.js example app by @Nutlope in https://github.com/Jarred-Sumner/bun/pull/389
- Fixing issues with example app READMEs by @Nutlope in https://github.com/Jarred-Sumner/bun/pull/397
- Add RSC to list of unsupported Next.js features in README by @Nutlope in https://github.com/Jarred-Sumner/bun/pull/334
- adding a template .gitignore by @MrBaggieBug in https://github.com/Jarred-Sumner/bun/pull/232
Landing page:
- Fix: long numbers + unused css by @michellbrito in https://github.com/Jarred-Sumner/bun/pull/367
- fix a11y issues on landing by @alexkuz in https://github.com/Jarred-Sumner/bun/pull/225
- Add a space in page.tsx by @eyalcohen4 in https://github.com/Jarred-Sumner/bun/pull/264
Internal:
- Allow setting LLVM_PREFIX and MIN_MACOS_VERSION as environment variables by @aslilac in https://github.com/Jarred-Sumner/bun/pull/237
- Use Node.js v18.x from NodeSource to use string.replaceAll method by @hnakamur in https://github.com/Jarred-Sumner/bun/pull/268
- refactor: wrap BigInt tests in describe block by @jsjoeio in https://github.com/Jarred-Sumner/bun/pull/278
- Add needed dependencies to Makefile devcontainer target by @hnakamur in https://github.com/Jarred-Sumner/bun/pull/269
- [strings] Fix typo in string_immutable.zig by @eltociear in https://github.com/Jarred-Sumner/bun/pull/274
README:
- Add troubleshooting for old intel CPUs by @coffee-is-power in https://github.com/Jarred-Sumner/bun/pull/386
- docs: add callout for typedefs with TypeScript by @josefaidt in https://github.com/Jarred-Sumner/bun/pull/276
- Added label for cpu by @isaac-mcfadyen in https://github.com/Jarred-Sumner/bun/pull/322
- chore(examples): Updates start doco #326 by @mrowles in https://github.com/Jarred-Sumner/bun/pull/328
- fix devcontainer starship installation by @shanehsi in https://github.com/Jarred-Sumner/bun/pull/345
- Update README.md by @PyBaker in https://github.com/Jarred-Sumner/bun/pull/370
- Add Bun logo in README by @DanielTolentino in https://github.com/Jarred-Sumner/bun/pull/228
- Fix
Safari's implementation
broken link by @F3n67u in https://github.com/Jarred-Sumner/bun/pull/257 - docs: Fix broken toc link by @hyp3rflow in https://github.com/Jarred-Sumner/bun/pull/218
New Contributors
- @addy made their first contribution in https://github.com/Jarred-Sumner/bun/pull/207
- @styfle made their first contribution in https://github.com/Jarred-Sumner/bun/pull/212
- @lucacasonato made their first contribution in https://github.com/Jarred-Sumner/bun/pull/215
- @logikaljay made their first contribution in https://github.com/Jarred-Sumner/bun/pull/236
- @intergalacticspacehighway made their first contribution in https://github.com/Jarred-Sumner/bun/pull/245
- @aslilac made their first contribution in https://github.com/Jarred-Sumner/bun/pull/237
- @F3n67u made their first contribution in https://github.com/Jarred-Sumner/bun/pull/257
- @WebReflection made their first contribution in https://github.com/Jarred-Sumner/bun/pull/254
- @MrBaggieBug made their first contribution in https://github.com/Jarred-Sumner/bun/pull/232
- @DanielTolentino made their first contribution in https://github.com/Jarred-Sumner/bun/pull/228
- @jsjoeio made their first contribution in https://github.com/Jarred-Sumner/bun/pull/278
- @hyp3rflow made their first contribution in https://github.com/Jarred-Sumner/bun/pull/218
- @hnakamur made their first contribution in https://github.com/Jarred-Sumner/bun/pull/269
- @egoarka made their first contribution in https://github.com/Jarred-Sumner/bun/pull/316
- @josefaidt made their first contribution in https://github.com/Jarred-Sumner/bun/pull/276
- @isaac-mcfadyen made their first contribution in https://github.com/Jarred-Sumner/bun/pull/322
- @mrowles made their first contribution in https://github.com/Jarred-Sumner/bun/pull/328
- @eyalcohen4 made their first contribution in https://github.com/Jarred-Sumner/bun/pull/264
- @Nutlope made their first contribution in https://github.com/Jarred-Sumner/bun/pull/334
- @eltociear made their first contribution in https://github.com/Jarred-Sumner/bun/pull/274
- @shanehsi made their first contribution in https://github.com/Jarred-Sumner/bun/pull/345
- @PyBaker made their first contribution in https://github.com/Jarred-Sumner/bun/pull/370
- @michellbrito made their first contribution in https://github.com/Jarred-Sumner/bun/pull/367
- @coffee-is-power made their first contribution in https://github.com/Jarred-Sumner/bun/pull/386
- @kjvalencik made their first contribution in https://github.com/Jarred-Sumner/bun/pull/392
Full Changelog: Jarred-Sumner/bun@bun-v0.1.1...bun-v0.1.2
Bun v0.1.1
What's New
- Web Streams -
ReadableStream
,WritableStream
,TransformStream
and more. This was a massive project. There are still some reliability things to fix, but I'm very happy with the performance, and I think you will be too. WebSocket
is now a global, powered by a custom WebSocket client- Dynamic
require()
- 50% faster TextEncoder
- ~30% faster React rendering in production due to a JSX transpiler optimization
- Streaming React SSR is now supported
- Dozens of small bug fixes to the HTTP server
- Discord interactions template by @evanwashere in https://github.com/Jarred-Sumner/bun/pull/2
- Group zsh completion options by type by @alexkuz in https://github.com/Jarred-Sumner/bun/pull/194
New Contributors
- @mjavadhpour made their first contribution in https://github.com/Jarred-Sumner/bun/pull/179
- @eswr made their first contribution in https://github.com/Jarred-Sumner/bun/pull/201
Full Changelog: Jarred-Sumner/bun@bun-v0.0.83...bun-v0.1.0
bun v0.0.83
To upgrade:
bun upgrade
Having trouble upgrading?
You can also try the install script.
curl https://bun.sh/install | bash
Thanks to:
- @kriszyp for tons of helpful feedback on how to improve Node-API support in bun
- @evanwashere for the idea & name for the
CFunction
abstraction - @adaptive for replacing
"wrangler@beta"
with"wrangler"
in the examples forbun add
- @littledivy for adding a couple missing packages to the build instructions
bun:sqlite
bun:sqlite
is a high-performance builtin SQLite module for bun.js.
It tends to be around 3x faster than the popular better-sqlite3
npm package
Note: in the benchmark I tweeted earlier, better-sqlite3
always returned arrays of arrays rather than arrays of objects, which was inconsistent with what bun:sqlite
& deno's x/sqlite were doing
Usage
import { Database } from "bun:sqlite";
const db = new Database("mydb.sqlite");
db.run(
"CREATE TABLE IF NOT EXISTS foo (id INTEGER PRIMARY KEY AUTOINCREMENT, greeting TEXT)"
);
db.run("INSERT INTO foo (greeting) VALUES (?)", "Welcome to bun!");
db.run("INSERT INTO foo (greeting) VALUES (?)", "Hello World!");
// get the first row
db.query("SELECT * FROM foo").get();
// { id: 1, greeting: "Welcome to bun!" }
// get all rows
db.query("SELECT * FROM foo").all();
// [
// { id: 1, greeting: "Welcome to bun!" },
// { id: 2, greeting: "Hello World!" },
// ]
// get all rows matching a condition
db.query("SELECT * FROM foo WHERE greeting = ?").all("Welcome to bun!");
// [
// { id: 1, greeting: "Welcome to bun!" },
// ]
// get first row matching a named condition
db.query("SELECT * FROM foo WHERE greeting = $greeting").get({
$greeting: "Welcome to bun!",
});
// [
// { id: 1, greeting: "Welcome to bun!" },
// ]
There are more detailed docs in Bun's README
bun:sqlite
's API is loosely based on @joshuawise's better-sqlite3
New in bun:ffi
CFunction
lets you call native library functions from a function pointer.
It works like dlopen
but its for cases where you already have the function pointer so you don't need to open a library. This is useful for:
- callbacks passed from native libraries to JavaScript
- using Node-API and bun:ffi together
import {CFunction} from 'bun:ffi';
const myNativeLibraryGetVersion: number | bigint = /* Somehow you got this function pointer */
const getVersion = new CFunction({
returns: "cstring",
args: [],
// ptr is required
// this is where the function pointer goes!
ptr: myNativeLibraryGetVersion,
});
getVersion();
getVersion.close();
linkSymbols
is like CFunction
except for when there are multiple functions. It returns the same object as dlopen
except ptr
is required and there is no path
import { linkSymbols } from "bun:ffi";
const [majorPtr, minorPtr, patchPtr] = getVersionPtrs();
const lib = linkSymbols({
// Unlike with dlopen(), the names here can be whatever you want
getMajor: {
returns: "cstring",
args: [],
// Since this doesn't use dlsym(), you have to provide a valid ptr
// That ptr could be a number or a bigint
// An invalid pointer will crash your program.
ptr: majorPtr,
},
getMinor: {
returns: "cstring",
args: [],
ptr: minorPtr,
},
getPatch: {
returns: "cstring",
args: [],
ptr: patchPtr,
},
});
const [major, minor, patch] = [
lib.symbols.getMajor(),
lib.symbols.getMinor(),
lib.symbols.getPatch(),
];
new CString(ptr)
should be a little faster due to using a more optimized function for getting the length of a string.
require.resolve()
Running require.resolve("my-module")
in Bun.js will now resolve the path to the module. Previously, this was not supported.
In browsers, it becomes the absolute filepath at build-time. In node, it's left in without any changes.
Internally, Bun's JavaScript transpiler transforms it to:
// input:
require.resolve("my-module");
// output
import.meta.resolveSync("my-module");
You can see this for yourself by running bun build ./file.js --platform=bun
"node:module"
module polyfill
Node's "module"
module lets you create require functions from ESM modules.
Bun now has a polyfill that implements a subset of the "module"
module.
Normally require()
in bun transforms statically at build-time to an ESM import
statement. That doesn't work as well for Node-API (napi) modules because they cannot be statically analyzed by a JavaScript parser (since they're not JavaScript).
For napi modules, bun uses a dynamic require function and the "module"
module exports a way to create those using the same interface as in Node.js
import { createRequire } from "module";
// this also works:
//import {createRequire} from 'node:module';
var require = createRequire(import.meta.url);
require.resolve("my-module");
// dynamic require is supported for:
// - .json files
// - .node files (napi modules)
require("my-napi-module");
This is mostly intended for improving Node-API compatibility with modules loaded from ESM.
As an extra thing, you can also use require()
this way for .json files.
Bun.Transpiler – pass objects to macros
Bun.Transpiler
now supports passing objects to macros.
import { Transpiler } from "bun";
import { parseCookie } from "my-cookie-lib";
import { Database } from "bun:sqlite";
const transpiler = new Transpiler();
const db = new Database("mydb.sqlite");
export default {
fetch(req) {
const transpiled = transpiler.transformSync(
`
import {getUser} from 'macro:./get-user';
export function Hello({name}) {
return <div>Hello {name}</div>;
}
export const HelloCurrentUser = <Hello {...getUser()} />;
`,
// passing contextual data to Bun.Transpiler
{
userId: parseCookie(req.headers.get("Cookie")).userId,
db: db,
}
);
return new Response(transpiled, {
headers: { "Content-Type": "application/javascript" },
});
},
};
Then, in get-user.js
:
// db, userId is now accessible in macros
export function getUser(expr, { db, userId }) {
// we can use it to query the database while transpiling
return db.query("SELECT * FROM users WHERE id = ? LIMIT 1").get(userId);
}
That inlines the returned current user into the JavaScript source code, producing output equivalent to this:
export function Hello({ name }) {
return <div>Hello {name}</div>;
}
// notice that the current user is inlined rather than a function call
export const HelloCurrentUser = <Hello name="Jarred" />;
Bug fixes
Buffer.from(arrayBuffer, byteOffset, length)
now works as expected (thanks to @kriszyp for reporting)
Misc
- Receiving and sending strings to Node-API modules should be a little faster
bun v0.0.81
To upgrade:
bun upgrade
Bun.js gets Node-API support
Node-API is 1.75x - 3x faster in Bun compared to Node.js 18 (in call overhead)
Just like in Node.js, to load a Node-API module, use require('my-npm-package')
or use process.dlopen
.
90% of the API is implemented, though it is certainly buggy right now.
Polyfills & new APIs in Bun.js v0.0.81
The following functions have been added:
import.meta.resolveSync
synchronously run the module resolver for the currently-referenced fileimport.meta.require
synchronously loads.node
or.json
modules and works with dynamic paths. This doesn't use ESM and doesn't run the transpiler, which is why regular js files are not supported. This is mostly an implementation detail for howrequire
works for Node-API modules, but it could also be used outside of that if you wantBun.gzipSync
,Bun.gunzipSync
,Bun.inflateSync
, andBun.deflateSync
which expose native bindings tozlib-cloudflare
. On macOS aarch64,gzipSync
is ~3x faster than in Node. This isn't wired up to the"zlib"
polyfill in bun yet
Additionally:
__dirname
is now supported for all targets (including browsers)__filename
is now supported for all targets (including browsers)Buffer.byteLength
is now implemented
Several packages using Node-API also use detect-libc
. Bun polyfills detect-libc
because bun doesn't support child_process
yet and this improves performance a little.
Bug fixes
bun v0.0.79
To upgrade:
bun upgrade
If you run into any issues with upgrading
Try running this:
curl https://bun.sh/install | bash
Highlights
"bun:ffi"
is a new bun.js core module that lets you use third-party native libraries written in languages that support the C ABI (Zig, Rust, C/C++ etc). It's like a foreign function interface API but fasterBuffer
(like in Node.js) is now a global, but the implementation is incomplete - see tracking issue. If you import"buffer"
, it continues to use the browser polyfill so this shouldn't be a breaking change- 2x faster
TextEncoder
&TextDecoder
thanks to some fixes to the vectorization (SIMD) code - Faster
TypedArray.from
. JavaScriptCore's implementation ofTypedArray.from
uses the code path for JS iterators when it could instead use an optimized code path for copying elements from an array, like V8 does. I have filed an upstream bug with WebKit about this, but I expect to do a more thorough fix for this in Bun and upstream that. For now, Bun reusesTypedArray.prototype.set
when possible - 17x faster
Uint8Array.fill
Bun.Transpiler
gets an API for removing & replacing exportsSHA512
,SHA256
,SHA128
, and more are now exposed in the"bun"
module and theBun
global. They use BoringSSL's optimized hashing functions.- Fixed a reliability bug with
new Response(Bun.file(path))
- Bun's HTTP server now has a
stop()
function. Before, there was no way to stop it without terminating the process 😆 - @evanwashere expose mmap size and offset option
- @jameslahm [node] Add more fs constants
The next large project for bun is a production bundler Tracking issue
New Contributors
- @jameslahm made their first contribution in https://github.com/Jarred-Sumner/bun/pull/144
- @lawrencecchen made their first contribution in https://github.com/Jarred-Sumner/bun/pull/151
bun:ffi
The "bun:ffi"
core module lets you efficiently call native libraries from JavaScript. It works with languages that support the C ABI (Zig, Rust, C/C++, C#, Nim, Kotlin, etc).
Get the locally-installed SQLite version number:
import { dlopen, CString, ptr, suffix, FFIType } from "bun:ffi";
const sqlite3Path = process.env.SQLITE3_PATH || `libsqlite3.${suffix}`;
const {
symbols: { sqlite3_libversion },
} = dlopen(sqlite3Path, {
sqlite3_libversion: {
returns: "cstring",
},
});
console.log("SQLite version", sqlite3_libversion());
FFI is really exciting because there is no runtime-specific code. You don't have to write a Bun FFI module (that isn't a thing). Use JavaScript to write bindings to native libraries installed with homebrew, with your linux distro's package manager or elsewhere. You can also write bindings to your own native code.
FFI has a reputation of being slower than runtime-specific APIs like napi – but that's not true for bun:ffi
.
Bun embeds a small C compiler that generates code on-demand and converts types between JavaScript & native code inline. A lot of overhead in native libraries comes from function calls that validate & convert types, so moving that to just-in-time compiled C using engine-specific implementation details makes that faster. Those C functions are called directly – there is no extra wrapper in the native code side of things.
Some bun:ffi
usecases:
- SQLite client
- Skia bindings so you can use Canvas API in bun.js
- Clipboard api
- Fast ffmpeg recording/streaming
- Postgres client (possibly)
- Use Pythons
"ndarray"
package from JavaScript (ideally via ndarray's C API and not just embedding Python in bun)
Later (not yet), bun:ffi will be integrated with bun's bundler and that will enable things like:
- Use hermes to strip Flow types for code transpiled in bun
- .sass support
Buffer
A lot of Node.js' Buffer module is now implemented natively in Bun.js, but it's not complete yet.
Here is a comparison of how long various functions take.
Replace & eliminate exports with Bun.Transpiler
For code transpiled with Bun.Transpiler
, you can now remove and/or replace exports with a different value.
const transpiler = new Bun.Transpiler({
exports: {
replace: {
// Next.js does this
getStaticProps: ["__N_SSG", true],
},
eliminate: ["localVarToRemove"],
},
treeShaking: true,
trimUnusedImports: true,
});
const code = `
import fs from "fs";
export var localVarToRemove = fs.readFileSync("/etc/passwd");
import * as CSV from "my-csv-parser";
export function getStaticProps() {
return {
props: { rows: CSV.parse(fs.readFileSync("./users-list.csv", "utf8")) },
};
}
export function Page({ rows }) {
return (
<div>
<h1>My page</h1>
<p>
<a href="/about">About</a>
</p>
<p>
<a href="/users">Users</a>
</p>
<div>
{rows.map((columns, index) => (
<span key={index}>{columns.join(" | ")} </span>
))}
</div>
</div>
);
}
`;
console.log(transpiler.transformSync(code));
Which outputs (this is the automatic react transform)
export var __N_SSG = true;
export function Page({ rows }) {
return jsxDEV("div", {
children: [
jsxDEV("h1", {
children: "My page"
}, undefined, false, undefined, this),
jsxDEV("p", {
children: jsxDEV("a", {
href: "/about",
children: "About"
}, undefined, false, undefined, this)
}, undefined, false, undefined, this),
jsxDEV("p", {
children: jsxDEV("a", {
href: "/users",
children: "Users"
}, undefined, false, undefined, this)
}, undefined, false, undefined, this),
jsxDEV("div", {
children: rows.map((columns, index) => jsxDEV("span", {
children: [
columns.join(" | "),
" "
]
}, index, true, undefined, this))
}, undefined, false, undefined, this)
]
}, undefined, true, undefined, this);
}
More new stuff
server.stop()
lets you stop bun's HTTP server- [bun.js] Add Bun.nanoseconds() to report time in nanos
Hashing functions powered by BoringSSL:
import {
SHA1,
MD5,
MD4,
SHA224,
SHA512,
SHA384,
SHA256,
SHA512_256,
} from "bun";
// hash the string and return as a Uint8Array
SHA1.hash("123456");
MD5.hash("123456");
MD4.hash("123456");
SHA224.hash("123456");
SHA512.hash("123456");
SHA384.hash("123456");
SHA256.hash("123456");
SHA512_256.hash("123456");
// output as a hex string
SHA1.hash(new Uint8Array(42), "hex");
MD5.hash(new Uint8Array(42), "hex");
MD4.hash(new Uint8Array(42), "hex");
SHA224.hash(new Uint8Array(42), "hex");
SHA512.hash(new Uint8Array(42), "hex");
SHA384.hash(new Uint8Array(42), "hex");
SHA256.hash(new Uint8Array(42), "hex");
SHA512_256.hash(new Uint8Array(42), "hex");
// incrementally update the hashing function value and convert it at the end to a hex string
// similar to node's API in require('crypto')
// this is not wired up yet to bun's "crypto" polyfill, but it really should be
new SHA1().update(new Uint8Array(42)).digest("hex");
new MD5().update(new Uint8Array(42)).digest("hex");
new MD4().update(new Uint8Array(42)).digest("hex");
new SHA224().update(new Uint8Array(42)).digest("hex");
new SHA512().update(new Uint8Array(42)).digest("hex");
new SHA384().update(new Uint8Array(42)).digest("hex");
new SHA256().update(new Uint8Array(42)).digest("hex");
new SHA512_256().update(new Uint8Array(42)).digest("hex");
Reliability improvements
bun v0.0.78
To upgrade:
bun upgrade
What's new:
You can now import
from "bun"
in bun.js. You can still use the global Bun
.
Before:
await Bun.write("output.txt", Bun.file("input.txt"))
After:
import {write, file} from 'bun';
await write("output.txt", file("input.txt"))
This isn't a breaking change – you can still use Bun
as a global same as before.
How it works
Bun's JavaScript printer replaces the "bun"
import specifier with globalThis.Bun
.
var {write, file} = globalThis.Bun;
await write("output.txt", file("input.txt"))
You'll probably want to update types too:
bun add bun-types
Bug fixes
- [fs] Add missing
isFile
andisDirectory
functions tofs.stat()
7cd3d13 - [js parser] Fix a code simplification bug that could happen when using
!
and comma operator - 4de7978 - [bun bun] Fix using
bun bun
with--platform=bun
set - 43b1866
Bug fixes from v0.0.77
- [bun dev] Fix race condition in file watcher
- [bun install] Fix falling back to copyfile when hardlink fails on linux due to differing filesystems - 74309a1
- [Bun.serve] When a
Bun.file
is not found and the error handler is not run, the default status code is now 404 - [Bun.serve] Fix hanging when
Bun.file
sent with sendfile and the request aborts or errors - [Bun.serve] Decrement the reference count for
FileBlob
sent via sendfile after the callback completes instead of before - [Bun.serve] Serve
.ts
and.tsx
files withtext/javascript
mime type by default instead of MPEG2 Video
bun v0.0.76
To upgrade:
bun upgrade
What's new
- Type definitions for better editor integration and TypeScript LSP! There are types for the runtime APIs now in the
bun-types
npm package. A PR for @types/bun is waiting review (feel free to nudge them). Bun.serve()
is a fast HTTP & HTTPS server that supports theRequest
andResponse
Web APIs. The server is a fork of uWebSocketsBun.write()
– one API for writing files, pipes, and copying files leveraging the fastest system calls available for the input & platform. It uses theBlob
Web API.Bun.mmap(path)
lets you read files as a live-updatingUint8Array
via the mmap(2) syscall. Thank you @evanwashere!!Bun.hash(bufferOrString)
exposes fast non-cryptographic hashing functions. Useful for things likeETag
, not for passwords.Bun.allocUnsafe(length)
creates a new Uint8Array ~3.5x faster than new Uint8Array, but it is not zero-initialized. This is similar to Node'sBuffer.allocUnsafe
, though without the memory pool currently- Several web APIs have been added, including
URL
- A few more examples have been added to the
examples
folder - Bug fixes to
fs.read()
andfs.write()
and some more tests for fs Response.redirect()
,Response.json()
, andResponse.error()
have been addedimport.meta.url
is now a file:// url stringBun.resolve
andBun.resolveSync
let you resolve the same asimport
does. It throws aResolveError
on failure (same asimport
)Bun.stderr
andBun.stdout
now return aBlob
SharedArrayBuffer
is now enabled (thanks @evanwashere!)- Updated Next.js version
New Web APIs in bun.js
Going forward, Bun will first try to rely on WebKit/Safari's implementations of Web APIs rather than writing new ones. This will improve Web API compatibility while reducing bun's scope, without compromising performance
These Web APIs are now available in bun.js and powered by Safari's implementation:
URL
URLSearchParams
ErrorEvent
Event
EventTarget
DOMException
Headers
uses WebKit's implementation now instead of a custom oneAbortSignal
(not wired up to fetch or fs yet, it exists but not very useful)AbortController
Also added:
reportError
(does not dispatch an"error"
event yet)
Additionally, all the builtin constructors in bun now have a .prototype
property (this was missing before)
Bun.serve
- fast HTTP server
For a hello world HTTP server that writes "bun!", Bun.serve
serves about 2.5x more requests per second than node.js on Linux:
Requests per second | Runtime |
---|---|
~64,000 | Node 16 |
~160,000 | Bun |
Bigger is better
Code
Bun:
Bun.serve({
fetch(req: Request) {
return new Response(`bun!`);
},
port: 3000,
});
Node:
require("http")
.createServer((req, res) => res.end("bun!"))
.listen(8080);
Usage
Two ways to start an HTTP server with bun.js:
export default
an object with afetch
function
If the file used to start bun has a default export with a fetch
function, it will start the http server.
// hi.js
export default {
fetch(req) {
return new Response("HI!");
},
};
// bun ./hi.js
fetch
receives a Request
object and must return either a Response
or a Promise<Response>
. In a future version, it might have an additional arguments for things like cookies.
Bun.serve
starts the http server explicitly
Bun.serve({
fetch(req) {
return new Response("HI!");
},
});
Error handling
For error handling, you get an error
function.
If development: true
and error
is not defined or doesn't return a Response
, you will get an exception page with a stack trace:
It will hopefully make it easier to debug issues with bun until bun gets debugger support. This error page is based on what bun dev
does.
If the error function returns a Response
, it will be served instead
Bun.serve({
fetch(req) {
throw new Error("woops!");
},
error(error: Error) {
return new Response("Uh oh!!\n" + error.toString(), { status: 500 });
},
});
If the error
function itself throws and development
is false
, a generic 500 page will be shown
Currently, there is no way to stop the HTTP server once started 😅, but that will be added in a future version.
The interface for Bun.serve
is based on what Cloudflare Workers does.
Bun.write() – optimizing I/O
Bun.write
lets you write, copy or pipe files automatically using the fastest system calls compatible with the input and platform.
interface Bun {
write(
destination: string | number | FileBlob,
input: string | FileBlob | Blob | ArrayBufferView
): Promise<number>;
}
Output | Input | System Call | Platform |
---|---|---|---|
file | file | copy_file_range | Linux |
file | pipe | sendfile | Linux |
pipe | pipe | splice | Linux |
terminal | file | sendfile | Linux |
terminal | terminal | sendfile | Linux |
socket | file or pipe | sendfile (if http, not https) | Linux |
file (path, doesn't exist) | file (path) | clonefile | macOS |
file | file | fcopyfile | macOS |
file | Blob or string | write | macOS |
file | Blob or string | write | Linux |
All this complexity is handled by a single function.
// Write "Hello World" to output.txt
await Bun.write("output.txt", "Hello World");
// log a file to stdout
await Bun.write(Bun.stdout, Bun.file("input.txt"));
// write the HTTP response body to disk
await Bun.write("index.html", await fetch("http://example.com"));
// this does the same thing
await Bun.write(Bun.file("index.html"), await fetch("http://example.com"));
// copy input.txt to output.txt
await Bun.write("output.txt", Bun.file("input.txt"));
Bug fixes
- Fixed a bug on Linux where sometimes the HTTP thread would incorrectly go to sleep, causing requests to hang forever 😢 . Previously, it relied on data in the queues to determine whether it should idle and now it increments a counter.
- Fixed a bug that sometimes caused
require
to produce incorrect output depending on how the module was used - Fixed a number of crashes in
bun dev
related to HMR & websockets - Jarred-Sumner/bun@daeede2 fs.openSync
now supportsmode
andflags
- Jarred-Sumner/bun@c73fcb0fs.read
andfs.write
were incorrectly returning the output offs/promises
versions, this is fixed- Fixed a crash that could occur during garbage collection when an
fs
function received a TypedArray as input. - Jarred-Sumner/bun@614f64b. This also improves performance of sending array buffers to native a little Response
's constructor previously readstatusCode
instead ofstatus
. This was incorrect and has been fixed.- Fixed a bug where
fs.stat
reported incorrect information on macOS x64 - Slight improvement to HMR reliability if reading large files or slow filesystems over websockets - 89cd35f
- Fixed a potential infinite loop when generating a sourcemap - fe973a5
improve performance of accessingBun.Transpiler
andBun.unsafe
29a759a
bun v0.0.72
To upgrade:
bun upgrade
What's new
This release adds source maps for JS output, several web APIs to bun.js (and HTMLRewriter
), parser support for ES2022 syntax, improves parsing speed for long strings, makes bun dev
10% faster on macOS and fixes a lot of crashes.
Note: the WASM build is not quite ready yet, but I'm working on it! The main thing I'm uncertain of is whether to release it with Bun.Transpiler
as the API, or with a partially-implemented esbuild
-compatible API. So if you would like to use it and have opinions there, do say
bun.js
Thanks to source maps, errors in bun.js show the source code instead of the transpiled code now:
Previously, it looked like this
Note the incorrect line numbers and the missing if (true)
branch – bun's transpiler removed the dead code, but that can make it harder to read the code
New APIs:
HTMLRewriter
– fast jQuery-like streaming HTML parser API in Cloudflare Workers, powered by LOLHTML (the same parser in cloudflare workers)setTimeout
,setInterval
,clearTimeout
, andclearInterval
Response.clone
,Request.clone
,Request.bodyUsed
,Response.bodyUsed
,Response.headers
atob
,btoa
Blob
, includingBlob.text()
,Blob.slice()
,Blob.arrayBuffer()
andRequest.blob()
,Response.blob()
console.trace()
is now implementedBun.inspect
lets you format likeconsole.log
but get back a stringBun.unsafe.arrayBufferToString(buffer)
lets you quickly & unsafely cast an ArrayBuffer-like object to a string. Useful when you've already encoded the string.
Misc:
console.log
support for JSX!ResolveError.prototype.toString()
andBuildError.prototype.toString()
work as expectedconsole.log
support forRequest
,Response
,Headers
- async node fs functions now have a compatibility wrapper that runs the sync version in the next tick. non-blocking support will come eventually
- Unlike the Web API,
FetchEvent.respondWith
will automatically await any promises now - Fixed UTF-8 bug with console.
{time, count, timeEnd, profile, profileEnd, count, countReset}
- Fix Program terminates with pending promises #122
- Fix a memory leak with microtasks - d0a9b40
- Fix bug causing async wasm compilation to never run - 7b8113c
bun dev
- Source Maps for non-bundled code
- 10% faster http requests on macOS
- Reduce HMR latency by using better syscalls (send multiple messages in one syscall with sendmsg)
- Improve HMR performance when multiple tabs are open (pooling websocket threads)
- Send “Date” header
- Fix crash on macOS that sometimes occurred when closing the tab
- Fixed several memory leaks and cases where bun would sometimes segfault
bun install
bun pm cache
prints the cache dir path- Fix bug when parsing package.json that has non-ascii characters
bun run
- Set $npm_config_user_agent
- Set $npm_package_json
- Set $NODE and $npm_node_exec path based on what’s available in $PATH
bun create
- Fix a crash due to allocation failure - 2d1538e
JavaScript Transpiler
- Source Maps support for unbundled code (app code)
- 69% faster at parsing long strings
- [microbenchmark] 10% faster at parsing HTML entity codes in JSX
- Support for static initialization blocks (ES2022)
- Support for private static class fields and methods (ES2022)
- Support for private static class brand checks (ES2022)
- Support for private identifiers (ES2019)
- Fix printing bug in strings that have certain escape sequences and non-ascii characters
- Always print escaped Unicode codepoints instead of the original. This more closely matches what Babel & esbuild do
- For TypeScript classes, match the semantics of useDefineForClassFields for fields and constructor arguments
Bun.Transpiler
:
autoImportJSX
flag lets you enable or disable importing auto-importing thejsxImportSource
.allowBunRuntime
flag lets you disable importing bun's runtime code. This is useful if you want to use bun as just a transpiler. It is disabled by default, as I would expect people to useBun.Transpiler
mostly for other environments than bun itself
Infrastructural changes
I started using the debug build of mimalloc, bun's memory allocator for the debug builds of bun and that uncovered a few otherwise difficult-to-reproduce crashes
bun v0.0.71
To upgrade:
bun upgrade
Having trouble?
# Try this
curl https://bun.sh/install | bash
Please let me know though if it doesn't work and you're on bun v0.0.69. bun v0.0.61 - v0.0.68 had issues with the HTTP client
Highlights:
- More reliable
bun install
: numerous bug fixes to linking, serialization, deserialization, extracting files. It probably works in many projects now. There are still a couple bugs that need to be fixed, no node-gyp yet, andgit
/github
dependencies don't work yet - "Copy as markdown" for error messages
- Macros can now be used like regular JavaScript, with automatic conversion of primitives & objects to Bun's AST
bun pm hash
returns a hash of the resolved all package@version in your lockfilebun install --global
lets you globally install npm packages with bun!- bug fixes to bun dev & bun run
TextEncoder
,TextDecoder
,process.exit
,crypto.randomUUID
,crypto.randomBytes
are now available in bun.js- Better support for Next.js v12.1
# Install a package globally with bun install
> bun install -g typescript
# "bun i" is shorthand for bun install
> bun i -g typescript
# It symlinks into your $BUN_INSTALL/bin folder
> which tsc
/Users/jarred/.bun/bin/tsc
# print the path of the global bin
> bun pm -g bin
/Users/jarred/.bun/bin
Lowlights:
- Breaking changes to
bun install
lockfile format change means your nextbun install
will invalidate existing ones. The changes improve the reliability of saving and loading the lockfile
"Copy as markdown" button for error messages
Before this release, bun dev
did not support displaying runtime errors. It only showed errors for build/ssr 🙈
Use macros like regular JavaScript
Now you can move code from runtime to build-time by writing ordinary javascript.
Input:
// This line is removed at build time
import {weatherIn} from 'macro:./weather'
// This function call is replaced with the value of `weatherIn(94609)` at build-time
const {current_condition: [{temp_F: degrees}]} = weatherIn(94609);
export default `It is ${degrees} in Oakland, California`
weather.js:
export async function weatherIn(call) {
const location = call.arguments[0];
return fetch(`https://wttr.in/${location.toString()}?format=j1`)
}
Output:
const {
current_condition: [{ temp_F: degrees }]
} = {
current_condition: [
{
temp_F: "42"
}
]
};
// once bun gets a minifier, this line would be all that remains
export default `It is ${degrees} in Oakland, California`;
Normally, this 48 KB of JSON would be fetched client-side
{
"current_condition": [
{
"FeelsLikeC": "4",
"FeelsLikeF": "39",
"cloudcover": "100",
"humidity": "79",
"localObsDateTime": "2022-02-25 03:18 AM",
"observation_time": "11:18 AM",
"precipInches": "0.0",
"precipMM": "0.0",
"pressure": "1026",
"pressureInches": "30",
"temp_C": "4",
"temp_F": "40",
"uvIndex": "1",
"visibility": "16",
"visibilityMiles": "9",
"weatherCode": "122",
"weatherDesc": [
{
"value": "Overcast"
}
],
"weatherIconUrl": [
{
"value": ""
}
],
"winddir16Point": "ENE",
"winddirDegree": "70",
"windspeedKmph": "7",
"windspeedMiles": "4"
}
],
"nearest_area": [
{
"areaName": [
{
"value": "Emeryville"
}
],
"country": [
{
"value": "United States of America"
}
],
"latitude": "37.831",
"longitude": "-122.284",
"population": "0",
"region": [
{
"value": "California"
}
],
"weatherUrl": [
{
"value": ""
}
]
}
],
"request": [
{
"query": "Lat 37.83 and Lon -122.26",
"type": "LatLon"
}
],
"weather": [
{
"astronomy": [
{
"moon_illumination": "24",
"moon_phase": "Last Quarter",
"moonrise": "03:03 AM",
"moonset": "12:25 PM",
"sunrise": "06:46 AM",
"sunset": "05:59 PM"
}
],
"avgtempC": "10",
"avgtempF": "49",
"date": "2022-02-25",
"hourly": [
{
"DewPointC": "2",
"DewPointF": "36",
"FeelsLikeC": "5",
"FeelsLikeF": "42",
"HeatIndexC": "7",
"HeatIndexF": "44",
"WindChillC": "5",
"WindChillF": "42",
"WindGustKmph": "11",
"WindGustMiles": "7",
"chanceoffog": "0",
"chanceoffrost": "0",
"chanceofhightemp": "0",
"chanceofovercast": "0",
"chanceofrain": "0",
"chanceofremdry": "82",
"chanceofsnow": "0",
"chanceofsunshine": "88",
"chanceofthunder": "0",
"chanceofwindy": "0",
"cloudcover": "4",
"humidity": "75",
"precipInches": "0.0",
"precipMM": "0.0",
"pressure": "1025",
"pressureInches": "30",
"tempC": "7",
"tempF": "44",
"time": "0",
"uvIndex": "1",
"visibility": "10",
"visibilityMiles": "6",
"weatherCode": "113",
"weatherDesc": [
{
"value": "Clear"
}
],
"weatherIconUrl": [
{
"value": ""
}
],
"winddir16Point": "WNW",
"winddirDegree": "300",
"windspeedKmph": "6",
"windspeedMiles": "4"
},
{
"DewPointC": "2",
"DewPointF": "35",
"FeelsLikeC": "6",
"FeelsLikeF": "42",
"HeatIndexC": "6",
"HeatIndexF": "42",
"WindChillC": "6",
"WindChillF": "42",
"WindGustKmph": "3",
"WindGustMiles": "2",
"chanceoffog": "0",
"chanceoffrost": "0",
"chanceofhightemp": "0",
"chanceofovercast": "0",
"chanceofrain": "0",
"chanceofremdry": "81",
"chanceofsnow": "0",
"chanceofsunshine": "93",
"chanceofthunder": "0",
"chanceofwindy": "0",
"cloudcover": "0",
"humidity": "78",
"precipInches": "0.0",
"precipMM": "0.0",
"pressure": "1026",
"pressureInches": "30",
"tempC": "6",
"tempF": "42",
"time": "300",
"uvIndex": "1",
"visibility": "10",
"visibilityMiles": "6",
"weatherCode": "113",
"weatherDesc": [
{
"value": "Clear"
}
],
"weatherIconUrl": [
{
"value": ""
}
],
"winddir16Point": "N",
"winddirDegree": "360",
"windspeedKmph": "2",
"windspeedMiles": "1"
},
{
"DewPointC": "1",
"DewPointF": "34",
"FeelsLikeC": "4",
"FeelsLikeF": "39",
"HeatIndexC": "5",
"HeatIndexF": "40",
"WindChillC": "4",
"WindChillF": "39",
"WindGustKmph": "9",
"WindGustMiles": "5",
"chanceoffog": "0",
"chanceoffrost": "0",
"chanceofhightemp": "0",
"chanceofovercast": "0",
"chanceofrain": "0",
"chanceofremdry": "91",
"chanceofsnow": "0",
"chanceofsunshine": "94",
"chanceofthunder": "0",
"chanceofwindy": "0",
"cloudcover": "0",
"humidity": "78",
...
bun v0.0.69
To upgrade:
bun upgrade
# If you run into problems, try this instead:
curl https://bun.sh/install | bash
bun v0.0.69
Highlights:
- Reliability improvements to bun's https client, which means reliability improvements to
bun install
,fetch()
,bun create
,bun upgrade
, and everything else depending on it bunfig.toml
lets you configure bun from a config file instead of only CLI argumentsimport foo from "./file.toml"
is now supported (thanks to bun's new TOML parser)- No longer need to install the
react-refresh
npm package for React Fast Refresh to work - Native support for Node.js
path
module bun dev
includes a default favicon, and the favicon becomes a red⚠️ on build error
HTTPS client
I rewrote the TLS part of bun's https client to match Chromium's behavior.
This fixes many bugs:
- On some websites using TLS 1.3, the https client would infinite loop during handshaking
- On some machines,
bun dev
would crash after 30 seconds due to bugs with the https client. Since it happened in a random interval between 0 and 30 seconds, it appeared to be in many places - On Ubuntu 20.04 when running Linux kernel 5.4 (the default for ubuntu server), sending http requests simply did not work at all. This was due to using io_uring APIs which are only available on Linux Kernel 5.6. Now, bun detects the linux kernel version in use and uses a (slower) fallback if the APIs are unavailable
- In some cases, it was closing socket file descriptors multiple times, leading to strange bugs like files failing to extract files during
bun install
or data corruption - In some cases, it was never closing socket file descriptors. This eventually led to errors about all sockets being busy
- Previously, bun cached the results returned from
getaddrinfo
. On Linux, this sometimes caused it to crash. Now bun does not cache it. This makes it a little slower, but this way of doing DNS resolution needs to be replaced with a non-blocking implementation regardless.
bunfig.toml
bunfig.toml is bun's configuration file.
Everything in it is optional. You don't need a bunfig.toml
to use bun, this exists so you don't have to pass flags to the CLI each time.
Options specific to bun install
will be added in a future release.
# Set a default framework to use
# By default, bun will look for an npm package like `bun-framework-${framework}`, followed by `${framework}`
framework = "next"
logLevel = "debug"
# publicDir = "public"
# external = ["jquery"]
[macros]
# Remap any import like this:
# import {graphql} from 'react-relay';
# To:
# import {graphql} from 'macro:bun-macro-relay';
react-relay = { "graphql" = "bun-macro-relay" }
[bundle]
saveTo = "node_modules.bun"
# Don't need this if `framework` is set, but showing it here as an example anyway
entryPoints = ["./app/index.ts"]
[bundle.packages]
# If you're bundling packages that do not actually live in a `node_modules` folder or do not have the full package name in the file path, you can pass this
"@bigapp/design-system" = true
[dev]
# Change the default port from 3000 to 5000
port = 5000
[define]
# Replace any usage of "process.env.bagel" with the string `lox`.
# The values are parsed as JSON, except single-quoted strings are supported and `'undefined'` becomes `undefined` in JS.
# This will probably change in a future release to be just regular TOML instead. It is a holdover from the CLI argument parsing.
"process.env.bagel" = "'lox'"
[loaders]
# When loading a .bagel file, run the JS parser
".bagel" = "js"
TOML imports
bun now has a custom TOML 1.0 parser, which means you can import .toml files from bun.
Note that parsing dates/timestamps is not implemented yet.
import config from 'my-config-file.toml';
console.assert(config.hi === "hello");
hi = "hello"
A future version might support importing top-level properties instead of only default
. I think supporting both ways would be a better DX.
bun dev
This release improves using bun for static sites. bun dev
now automatically looks for .html
files in the same folder as code. Previously, .html
files needed to be in either public
or static
You no longer need to install the react-refresh
npm package to use React Fast Refresh with bun. bun embeds it into bun's binary and automatically enables it if resolving "react"
(or otherwise, the JSX import source) is successful
bun sets a default favicon so you can more easily see which tab is your dev server:
Path module
bun.js gets native support for Node's path
module. This is a performance improvement, but it's also good for consistency & reliability. It means that resolving file paths in JavaScript is consistent with native code.
// Any of these work
import * as path from "node:path";
import * as path from "path";
const path = require("path");
As part of that work, a bug was fixed when generating relative file paths where, in some cases, it would cut off the first letter if the destination
file path did not have any folders in common with the from
file path
Misc:
- Missing newline in errors in bun install - 1064b9d
- Fix JS printing edgecase with nested vars using destructuring - d47e0de
- Fix CommonJS <> ESM interop edgecase when
require()
bundled code - 73449bf - bun.js resolve dynamic imports lazily - Jarred-Sumner/bun@0e0bfe9
- Reduced memory usage for object pools. For many things, bun uses object pools to spend less time allocating and deallocating memory. Once allocated, these are never freed. Now object pools have a limit to how many are kept alive in the pool. 213960a
- Use a special heap for the https client
Thanks to:
- @minkbazink for the idea to call bun's config bunfig.toml and @robpalmer2
- @alexkuz for making it a little easier compile debug builds on mac Jarred-Sumner/bun@aad33c2