We're hiring C/C++ and Zig engineers to build the future of JavaScript! Join our team →
As a reminder: 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 in case you missed it:
v0.6.0
- Introducingbun build
, Bun's new JavaScript bundler.v0.6.2
- Performance boosts: 20% fasterJSON.parse
, up to 2x fasterProxy
andarguments
.v0.6.3
- Implementednode:vm
, lots of fixes tonode:http
andnode:tls
.v0.6.4
- Implementedrequire.cache
,process.env.TZ
, and 80% fasterbun test
.v0.6.5
- Native support for CommonJS modules (previously, Bun did CJS to ESM transpilation),v0.6.6
-bun test
improvements, including Github Actions support,test.only()
,test.if()
,describe.skip()
, and 15+ moreexpect()
matchers; also streaming file uploads usingfetch()
.v0.6.7
- Node.js compatibility improvements to unblock Discord.js, Prisma, and Puppeteerv0.6.8
- IntroducedBun.password
, mocking inbun test
, andtoMatchObject()
v0.6.9
- Less memory usage and support for non-ascii filenamesv0.6.10
-fs.watch()
,bun install
bug fixes,bun test
features, and improved CommonJS supportv0.6.11
- Addressed a release build issue fromv0.6.10
.v0.6.12
- Sourcemap support inError.stack
,Bun.file().exists()
, and Node.js bug fixes.
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
Mock Date
in bun test
You can now mock the value of new Date()
in Bun's test runner. This will affect any API that can retreive the system time, including: Date.now()
, new Date()
, and Intl.DateTimeFormat().format()
.
import { test, expect, setSystemTime } from "bun:test";
test("time travel", () => {
const past = new Date("2022-07-05");
setSystemTime(past);
expect(new Date()).toBe(past);
expect(Date.now()).toBe(past.getTime());
expect(new Intl.DateTimeFormat("en-US").format()).toBe("07/05/2022");
setSystemTime(); // resets
expect(Date.now()).toBeGreaterThan(past.getTime());
});
Unlike in Jest, the Date
object doesn't mutate when you mock the time. This prevents a whole class of confusing test-only bugs.
import { test, expect } from "bun:test";
test("Date.prototype", () => {
const OriginalDate = Date;
setSystemTime(new Date("2022-07-05"));
// both pass in Bun, but fail in Jest
expect(OriginalDate).toBe(Date);
expect(OriginalDate.now).toBe(Date.now);
});
10x faster Buffer.toString("base64")
In the next version of Bun
— Jarred Sumner (@jarredsumner) July 2, 2023
buffer.toString('base64') gets 10x faster pic.twitter.com/4vAiZF60oK
Improvements to node:tls
and node:net
@cirospaciari made lots of improvements to Bun's implementation of node:tls
and node:net
. This unlocks various npm packages that were dependent on these changes.
Postgres with TLS works
You can now use postgres
package to connect to a Postgres database using TLS. Previously, you could connect without TLS, but there were some outstanding issues that prevented TLS from working.
import { postgres } from "postgres";
const sql = postgres(process.env.DATABASE_URI);
const name = "ThePrimeagen",
age = 69;
const users = await sql`
select
name,
age
from users
where
name like ${name + "%"}
and age > ${age}
`;
console.log(users); // [{ name: "ThePrimeagen", age: 69 }]
Nodemailer works
You can now use the nodemailer
package to send emails.
import nodemailer from "nodemailer";
nodemailer.createTestAccount(async (err, account) => {
const transporter = nodemailer.createTransport({
host: account.smtp.host,
port: account.smtp.port,
secure: account.smtp.secure,
debug: true,
auth: {
user: account.user,
pass: account.pass,
},
});
let info = await transporter.sendMail({
from: '"Fred Foo 👻" <foo@example.com>',
to: "example@gmail.com",
subject: "Hello ✔",
text: "Hello world?",
html: "<b>Hello world?</b>",
});
console.log("Message sent: %s", info.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
});
.isUtf8()
and .isAscii()
You can now use isUtf8()
and isAscii()
from Node's buffer
module.
import { test, expect } from "bun:test";
import { isUtf8, isAscii } from "node:buffer";
test("isUtf8 and isAscii", () => {
expect(isUtf8(new Buffer("What did the 🦊 say?"))).toBeTrue();
expect(isAscii(new Buffer("What did the 🦊 say?"))).toBeFalse();
});
Slightly less memory for HTTP requests
Bun now uses 8 less bytes per HTTP request thanks to Zig's packed struct. This allows us to store the same information in a more memory efficient layout.
In the example below, each bool
is stored as 1 byte.
const Request = struct {
is_transfer_encoding: bool,
is_waiting_body: bool,
// ...
aborted: bool,
};
Now, with a packed struct, each bool
is stored as 1 bit.
const Request = struct {
const Flags = packed struct {
is_transfer_encoding: bool,
is_waiting_body: bool,
// ...
aborted: bool,
};
flags: Flags,
};
WebSocket client reliability improvements
This release fixes a number of bugs in Bun's WebSocket
client implementation.
Zero-length messages are supported
Did you know that you can send & receive zero-length messages with WebSockets? Previously, Bun would ignore those, but now they're supported.
const ws = new WebSocket("wss://ws.postman-echo.com/raw");
ws.onopen = () => {
ws.send("");
ws.send(new ArrayBuffer(0));
};
ws.onmessage = (event) => {
console.log(event.data); // ""
console.log(event.data); // ArrayBuffer(0)
};
Initial payload race condition fix
Previously, when the initial HTTP response was received and contained websocket message(s) were sent in the same event loop tick, Bun would sometimes ignore the messages. This is now fixed.
Similarly, there was an edgecase where the initial message could be dispatched after a subsequent mesage was received (the 2nd message would appear before the 1st message). This has also been fixed.
Bug fixes
Changed .toEqual()
to now ignore private properties (prefixed with #
).
import { test, expect } from "bun:test";
test("toEqual() with #property", () => {
class Foo {
bar = 1;
#baz = "";
}
class Bar {
bar = 1;
}
expect(new Foo()).toEqual(new Bar());
});
Fixed crash with workspace:
dependency in package.json.
Previously, if you ran bun add
with the following package.json
, Bun would crash. This is now fixed.
{
"dependencies": {
"foo": "workspace:bar"
}
}
Fixed zero-length environment variables not working.
Previously, if you ran bun run
with the following .env
file, Bun would not detect the environment variable. This is now fixed.
FOO=
Fixed wrong text decoding from HTMLRewriter
.
Previously, if you can the following code in Bun, it would output the wrong result. This is now fixed.
new HTMLRewriter()
.on("p", {
element(element) {
console.log(element.getAttribute("id"));
},
})
.transform(new Response('<p id="Šžõäöü"></p>'));
// Before fix: Šžõäöü
// After fix: Šžõäöü
Fixed overloads for Buffer.toString()
.
Previously, if you used toString()
on a Node.js Buffer
, Bun would not properly handle the 2nd overload. The 1st overload specifies a start and end, whereas the 2nd overload specified an offset and length instead of end.
interface Buffer {
toString(encoding?: BufferEncoding, start?: number, end?: number): string;
toString(offset: number, length: number, encoding?: BufferEncoding): string;
}
const { Buffer } = require("node:buffer");
const buf = Buffer.from("hello world", "latin1");
console.log(buf.toString("latin1", 1, 2));
console.log(buf.toString(1, 2, "latin1"));
Thanks to @Hanaasagi for fixing!
Fixed missing export from node:http
module.
We were missing two exports. Oops!
var defaultObject = {
globalAgent,
+ ClientRequest,
+ OutgoingMessage,
[Symbol.for("CommonJS")]: 0,
};
Thanks to @stijnvanhulle for fixing!
Other bug fixes
Fixed utf-8 decoding for some Node-APIs.
Fixed file descriptors leaking when a new JavaScript file is loaded.