Bun 1.0 is finally here.
Bun is a fast, all-in-one toolkit for running, building, testing, and debugging JavaScript and TypeScript, from a single file to a full-stack application. Today, Bun is stable and production-ready.
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
Upgrade Bun
bun upgrade
Bun is an all-in-one toolkit
We love JavaScript. It's mature, it moves fast, and its developer community is vibrant and passionate. It's awesome.
However, since Node.js debuted 14 years ago, layers and layers of tooling have accumulated on top of each other. And like any system that grows and evolves without centralized planning, JavaScript tooling has become slow and complex.
Why Bun exists
Bun's goal is simple: eliminate slowness and complexity without throwing away everything that's great about JavaScript. Your favorite libraries and frameworks should still work, and you shouldn't need to unlearn the conventions you're familiar with.
You will however need to unlearn the many tools that Bun makes unnecessary:
Node.js — Bun is a drop-in replacement for Node.js, so you don't need:
node
npx
—bunx
is 5x fasterdotenv
,cross-env
— Bun reads.env
files by defaultnodemon
,pm2
— built-in watch modews
— built-in WebSocket servernode-fetch
,isomorphic-fetch
— built-infetch
Transpilers — Bun can run .js
, .ts
, .cjs
, .mjs
, .jsx
, and .tsx
files, which can replace:
tsc
— (but you can keep it for typechecking!)babel
,.babelrc
,@babel/preset-*
ts-node
,ts-node-esm
tsx
Bundlers — Bun is a JavaScript bundler with best-in-class performance and an esbuild-compatible plugin API, so you don't need:
esbuild
webpack
parcel
,.parcelrc
rollup
,rollup.config.js
Package managers — Bun is an npm-compatible package manager with familiar commands. It reads your package.json
and writes to node_modules
, just like other package managers, so you can replace:
npm
,.npmrc
,package-lock.json
yarn
,yarn.lock
pnpm
,pnpm.lock
,pnpm-workspace.yaml
lerna
Testing libraries — Bun is a Jest-compatible test runner with support for snapshot testing, mocking, and code coverage, so you no longer need:
jest
,jest.config.js
ts-jest
,@swc/jest
,babel-jest
jest-extended
vitest
,vitest.config.ts
While these tools are each good in their own right (mostly), using them all together inevitably creates fragility and a slow developer experience. They perform a lot of redundant work; when you run jest
, your code will be parsed 3+ times by various tools! And the duct tape, plugins, and adapters required to stitch everything together always frays eventually.
Bun is a single integrated toolkit that avoids these integration problems. Each tool in this toolkit provides a best-in-class developer experience, from performance to API design.
Bun is a JavaScript runtime
Bun is a fast JavaScript runtime. Its goal is to make the experience of building software faster, less frustrating, and more fun.
Node.js compatibility
Bun is a drop-in replacement for Node.js. That means existing Node.js applications and npm packages just work in Bun. Bun has built-in support for Node APIs, including:
- built-in modules like
fs
,path
, andnet
, - globals like
__dirname
andprocess
, - and the Node.js module resolution algorithm. (e.g.
node_modules
)
While perfect compatibility with Node.js isn't possible — looking at you node:v8
— Bun can run virtually any Node.js application in the wild.
Bun is tested against test suites of the most popular Node.js packages on npm. Server frameworks like Express, Koa, and Hono just work. As do applications built using the most popular full-stack frameworks. Collectively, these libraries and frameworks touch every part of Node.js's API surface that matters.
Note — For a detailed breakdown of Node.js compatibility, check out: bun.sh/nodejs.
Speed
Bun is fast, starting up to 4x faster than Node.js. This difference is only magnified when running a TypeScript file, which requires transpilation before it can be run by Node.js.
Unlike Node.js and other runtimes that are built using Google's V8 engine, Bun is built using Apple's WebKit engine. WebKit is the engine that powers Safari and is used by billions of devices every day. It's fast, efficient, and has been battle-tested for decades.
TypeScript and JSX support
Bun has a JavaScript transpiler that's baked into the runtime. That means you can run JavaScript, TypeScript, and even JSX/TSX files, no dependencies needed.
bun index.ts
bun index.jsx
bun index.tsx
ESM & CommonJS compatibility
The transition from CommonJS to ES modules has been slow and full of terrors. After ESM was introduced, Node.js took 5 years before supporting it without an --experimental-modules
flag. Regardless, the ecosystem is still full of CommonJS.
Bun supports both module systems, all the time. No need to worry about file extensions, .js
vs .cjs
vs .mjs
, or including "type": "module"
in your package.json
.
You can even use import
and require()
, in the same file. It just works.
import lodash from "lodash";
const _ = require("underscore");
Web APIs
Bun has built-in support for the Web standard APIs that are available in browsers, such as fetch
, Request
, Response
, WebSocket
, and ReadableStream
.
const response = await fetch("https://example.com/");
const text = await response.text();
You no longer need to install packages like node-fetch
and ws
. Bun's built-in Web APIs are implemented in native code, and are faster and more reliable than the third-party alternatives.
Hot reloading
Bun makes it easier for you to be productive as a developer. You can run Bun with --hot
to enable hot reloading, which reloads your application when files change.
bun --hot server.ts
Unlike tools that hard-restart the entire process, like nodemon
, Bun reloads your code without terminating the old process. That means HTTP and WebSocket connections don't disconnect and state isn't lost.
Plugins
Bun is designed to be highly-customizable.
You can define plugins to intercept imports and perform custom loading logic. A plugin can add support for additional file types, like .yaml
or .png
. The Plugin API is inspired by esbuild, which means that most esbuild plugins will just work in Bun.
import { plugin } from "bun";
plugin({
name: "YAML",
async setup(build) {
const { load } = await import("js-yaml");
const { readFileSync } = await import("fs");
build.onLoad({ filter: /\.(yaml|yml)$/ }, (args) => {
const text = readFileSync(args.path, "utf8");
const exports = load(text) as Record<string, any>;
return { exports, loader: "object" };
});
},
});
Bun APIs
Bun ships with highly-optimized, standard-library APIs for the things you need most as a developer.
In contrast to Node.js APIs, which exist for backwards compatibility, these Bun-native APIs are designed to be fast and easy-to-use.
Bun.file()
Use Bun.file()
to lazily load a File
at a particular path.
const file = Bun.file("package.json");
const contents = await file.text();
It returns a BunFile
, which extends the Web standard File
. The file contents can be lazily loaded in various formats.
const file = Bun.file("package.json");
await file.text(); // string
await file.arrayBuffer(); // ArrayBuffer
await file.blob(); // Blob
await file.json(); // {...}
Bun reads files up to 10x times faster than Node.js.
Bun.write()
Use Bun.write()
is a single, flexible API for writing almost anything to disk — string, binary data, Blobs
, even a Response
object.
await Bun.write("index.html", "<html/>");
await Bun.write("index.html", Buffer.from("<html/>"));
await Bun.write("index.html", Bun.file("home.html"));
await Bun.write("index.html", await fetch("https://example.com/"));
Bun writes files up to 3x faster than Node.js.
Bun.serve()
Use Bun.serve()
to spin up an HTTP server, WebSocket server, or both. It's based on familiar Web-standard APIs like Request
and Response
.
Bun.serve({
port: 3000,
fetch(request) {
return new Response("Hello from Bun!");
},
});
Bun can serve 4x more requests per second than Node.js.
You can also configure TLS using the tls
option.
Bun.serve({
port: 3000,
fetch(request) {
return new Response("Hello from Bun!");
},
tls: {
key: Bun.file("/path/to/key.pem"),
cert: Bun.file("/path/to/cert.pem"),
}
});
To support WebSockets alongside HTTP, simply define an event handler inside websocket
. Compare this with Node.js, which doesn't provide a built-in WebSocket API and requires a third-party dependency like ws
.
Bun.serve({
fetch() { ... },
websocket: {
open(ws) { ... },
message(ws, data) { ... },
close(ws, code, reason) { ... },
},
});
Bun can serve 5x more messages per second than ws
on Node.js.
bun:sqlite
Bun has built-in support for SQLite. It has an API that's inspired by better-sqlite3
, but is written in native code to be faster.
import { Database } from "bun:sqlite";
const db = new Database(":memory:");
const query = db.query("select 'Bun' as runtime;");
query.get(); // => { runtime: "Bun" }
Bun can query SQLite up to 4x faster than better-sqlite3
on Node.js.
Bun.password
Bun also supports APIs for common, but complex things you wouldn't want to implement yourself.
You can use Bun.password
to hash and verify passwords using bcrypt or argon2, no external dependencies required.
const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password);
// => $argon2id$v=19$m=65536,t=2,p=1$tFq+9AVr1bfPxQdh...
const isMatch = await Bun.password.verify(password, hash);
// => true
Bun is a package manager
Even if you don't use Bun as a runtime, Bun's built-in package manager can speed up your development workflow. Gone are the days of staring at that npm
spinner as your dependencies install.
Bun may look like the package managers you're used to —
bun install
bun add <package> [--dev|--production|--peer]
bun remove <package>
bun update <package>
— but it doesn't feel like them.
Wow, bun install is ridiculously fast
— Steve (Builder.io) (@Steve8708) August 21, 2022
So fast I didn't believe it worked. I had to stare at the console for a while to fully believe that the package install actually happened
Feels really nice to use, huge kudos to @jarredsumner
Install speeds
Bun is orders of magnitude faster than npm
, yarn
, and pnpm
. It uses a global module cache to avoid redundant downloads from the npm registry and uses the fastest system calls available on each operating system.
Running scripts
Chances are, you haven't ran a script directly with node
in a while. Instead, we often use our package managers to interface with the frameworks and CLIs to build our apps.
npm run dev
You can replace npm run
with bun run
to save 150ms milliseconds every time you run a command.
These numbers may all seem small, but when running CLIs, the perceptual difference is huge. Running npm run
is noticably laggy—
—whereas bun run
feels instantaneous.
And we're not just picking on npm. In fact, bun run <command>
is faster than the equivalent in yarn
and pnpm
.
Script runner | Avg. time |
---|---|
npm run | 176ms |
yarn run | 131ms |
pnpm run | 259ms |
bun run | 7ms 🚀 |
Bun is a test runner
If you’ve written tests in JavaScript before, you’re probably familiar with Jest, which pioneered the "expect"-style APIs.
Bun has a built-in testing module bun:test
that is fully Jest-compatible.
import { test, expect } from "bun:test";
test("2 + 2", () => {
expect(2 + 2).toBe(4);
});
You can run your tests with the bun test
command.
bun test
You also get all the benefits of the Bun runtime, including TypeScript and JSX support.
Migration from Jest or Vitest is easy. Any imports from @jest/globals
or vitest
will be internally re-mapped to bun:test
, so everything works, even without code changes.
import { test } from "@jest/globals";
describe("test suite", () => {
// ...
});
In a benchmark against the test suite for zod
, Bun was 13x faster than Jest and 8x faster than than Vitest.
Bun's matchers are implemented in fast native code — expect().toEqual()
in Bun is 100x faster than Jest and 10x faster than Vitest.
To get started, you can speed up your CI using bun test
. In Github Actions, use the official oven-sh/setup-bun
action.
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: oven-sh/setup-bun@v1
- run: bun test
And to make things that even nicer, Bun automatically adds annotations to your test failures, so your CI logs are easy to read.
Bun is a bundler
Bun is a JavaScript and TypeScript bundler and minifier that can be used to bundle code for the browser, Node.js, and other platforms.
bun build ./index.tsx --outdir ./build
It's heavily inspired by esbuild and provides a compatible plugin API.
import mdx from "@mdx-js/esbuild";
Bun.build({
entrypoints: ["index.tsx"],
outdir: "build",
plugins: [mdx()],
});
Bun's plugin API is universal, meaning it works for both the bundler and the runtime. So that .yaml
plugin from earlier can be used here to support .yaml
imports during bundling.
Using esbuild's own benchmarks, Bun is 1.75x faster than esbuild, 150x faster than Parcel 2, 180x times faster than Rollup + Terser, and 220x times faster than Webpack.
Since Bun's runtime and bundler are integrated, it means that Bun can do things that no other bundler can do.
Bun introduces JavaScript macros, a mechanism for running JavaScript functions at bundle-time. The value returned from these functions are directly inlined into your bundle.
import { getRelease } from "./release.ts" with { type: "macro" };
// The value of `release` is evaluated at bundle-time,
// and inlined into the bundle, not run-time.
const release = await getRelease();
export async function getRelease(): Promise<string> {
const response = await fetch(
"https://api.github.com/repos/oven-sh/bun/releases/latest"
);
const { tag_name } = await response.json();
return tag_name;
}
bun build index.ts
// index.ts
var release = await "bun-v1.0.0";
This is a new paradigm for bundling JavaScript, and we're excited to see what you build with it.
Bun more thing...
Bun provides native builds for macOS and Linux, but there's been one notable absence: Windows. Previously, to run Bun on Windows, you would need to install Windows Subsystem for Linux... but not anymore.
For the first time, we're excited to release an experimental, native build of Bun for Windows.
While the macOS and Linux builds of Bun are production-ready, the Windows build is highly experimental. At the moment, only the JavaScript runtime is supported; the package manager, test runner, and bundler have been disabled until they are more stable. The performance has also not been optimized — yet.
We'll be rapidly improving support for Windows over the coming weeks. If you're excited about Bun for Windows, we'd encourage you to join the #windows
channel on our Discord for updates.
Thank you
Bun's journey to 1.0 would have not been possible without Bun's amazing team of engineers and the growing community of contributors.
We'd like to thank those who helped us get here.
- Node.js & its contributors: Software is built on the shoulder of giants.
- WebKit & its contributors, especially Constellation: Thank you for making WebKit faster, you're amazing.
- The nearly 300 contributors who have helped build Bun over the past two years!
What's next?
Bun 1.0 is just the beginning.
We’re developing a new way to deploy JavaScript and TypeScript to production. And we’re hiring low-level systems engineers if you want to help us build the future of JavaScript.
You can also:
- Join our Discord server to hear the latest about Bun.
- Follow us on X/Twitter for JavaScript memes and daily updates from Jarred and the team.
- Star us on Github — it pays the bills! (/s)
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
Upgrade Bun
bun upgrade
Changelog since v0.8
If you were using Bun before 1.0, there are a few changes since Bun 0.8.
- Next.js, Astro, and Nest.js are now supported!
- The deprecated
bun dev
command has been removed. Runningbun dev
will now run the"dev"
script in your package.json.
Bun now supports the following Node.js APIs:
child_process.fork()
and IPC.fs.cp()
andfs.cpSync()
.fs.watchFile()
andfs.unwatchFile()
.- Unix sockets in
node:http
.
Hot reloading now supports Bun.serve()
. Previously, this was only possible if the server was defined as a default export
.
Bun.serve({
fetch(request) {
return new Response("Reload!");
},
})
bun --hot server.ts