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 #144
- @lawrencecchen made their first contribution in #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");