Table of Contents
Bun is a fast JavaScript all-in-one toolkit, runtime, package manager, bundler, test runner.
It was being developed to, test, run, and bundle JavaScript & TypeScript projects.
Bun is also known as an all-in-one JavaScript runtime & toolkit designed for speed, complete with a bundler, test runner, and Node.js-compatible package manager.
How to install Bun?
To Install Bun v1.0.0, use the code below, currently it only supports installation on macOS, Linux, and WSL.
curl -fsSL https://bun.sh/install | bash
$ bun run
Bun is a JavaScript runtime.
Bun is a new JavaScript runtime built from scratch to serve the modern JavaScript ecosystem. It has three major design goals:
- Speed. Bun starts fast and runs fast. It extends JavaScriptCore, the performance-minded JS engine built for Safari. As computing moves to the edge, this is critical.
- Elegant APIs. Bun provides a minimal set of highly-optimimized APIs for performing common tasks, like starting an HTTP server and writing files.
- Cohesive DX. Bun is a complete toolkit for building JavaScript apps, including a package manager, test runner, and bundler.
Bun is designed as a drop-in replacement for Node.js. It natively implements hundreds of Node.js and Web APIs, including fs
, path
, Buffer
and more.
The goal of Bun is to run most of the world’s server-side JavaScript and provide tools to improve performance, reduce complexity, and multiply developer productivity.
The APIs you need.
Start an HTTP server
index.tsx
const server = Bun.serve({
port: 3000,
fetch(request) {
return new Response("Welcome to Bun!");
},
});
console.log(`Listening on localhost:${server.port}`);
Start a WebSocket server
index.tsx
const server = Bun.serve<{ authToken: string; }>({
fetch(req, server) {
// use a library to parse cookies
const cookies = parseCookies(req.headers.get("Cookie"));
server.upgrade(req, {
data: { authToken: cookies['X-Token'] },
});
},
websocket: {
// handler called when a message is received
async message(ws, message) {
console.log(`Received: ${message}`);
const user = getUserFromToken(ws.data.authToken);
await db.Message.insert({
message: String(message),
userId: user.id,
});
},
},
});
console.log(`Listening on localhost:${server.port}`);
Read and write files
index.tsx
const file = Bun.file(import.meta.dir + '/package.json'); // BunFile
const pkg = await file.json(); // BunFile extends Blob
pkg.name = 'my-package';
pkg.version = '1.0.0';
await Bun.write(file, pkg);
Hash a password
index.tsx
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
Bundle for the browser
bundle.tsx
await Bun.build({
entrypoints: ["./index.tsx"],
outdir: "./build",
minify: true,
plugins: [ /* ... */ ]
})
Write a test
index.tsx
import { describe, expect, test, beforeAll } from "bun:test";
beforeAll(() => {
// setup tests
});
describe("math", () => {
test("addition", () => {
expect(2 + 2).toBe(4);
expect(7 + 13).toMatchSnapshot();
});
});
File system routing
index.tsx
const router = new Bun.FileSystemRouter({
style: "nextjs",
dir: "/path/to/pages"
});
const match = router.match("/blog/my-cool-post");
match.filePath; // "/path/to/pages/blog/[slug].tsx",
match.kind; // "dynamic"
match.params; // { slug: "my-cool-post" }
Read a stream
index.tsx
const response = await fetch("https://bun.sh");
await Bun.readableStreamToArrayBuffer(response.body); // => ArrayBuffer
await Bun.readableStreamToBlob(response.body); // => Blob
await Bun.readableStreamToJSON(response.body); // => object
await Bun.readableStreamToText(response.body); // => string
await Bun.readableStreamToArray(response.body); // => unknown[]
Spawn a child process
index.tsx
const proc = Bun.spawn(["echo", "hello"], {
cwd: "./path/to/subdir", // specify a working direcory
env: { ...process.env, FOO: "bar" }, // specify environment variables
onExit(proc, exitCode, signalCode, error) {
// exit handler
},
});
const text = await new Response(proc.stdout).text();
console.log(text); // => "hello"
Call a C function
index.tsx
import { dlopen, FFIType, suffix } from "bun:ffi";
// `suffix` is either "dylib", "so", or "dll" depending on the platform
const path = `libsqlite3.${suffix}`;
const {
symbols: {
sqlite3_libversion, // the function to call
},
} = dlopen(path, {
sqlite3_libversion: {
args: [], // no arguments
returns: FFIType.cstring, // returns a string
},
});
console.log(`SQLite 3 version: ${sqlite3_libversion()}`);
Install Bun in 3 Simple Steps
Step 1 (Install Bun)
curl -fsSL https://bun.sh/install | bash
Step 2 (Write your code)
index.tsx
const server = Bun.serve({
port: 3000,
fetch(request) {
return new Response("Welcome to Bun!");
},
});
console.log(`Listening on localhost:${server.port}`);
Step 3 (Run the file)
bun index.tsx
Quickstart
Let’s write a simple HTTP server using the built-in Bun.serve
API. First, create a fresh directory.
mkdir quickstart
cd quickstart
Run bun init
to scaffold a new project. It’s an interactive tool; for this tutorial, just press enter
to accept the default answer for each prompt.
bun init
bun init helps you get started with a minimal project and tries to
guess sensible defaults. Press ^C anytime to quit.
package name (quickstart):
entry point (index.ts):
Done! A package.json file was saved in the current directory.
+ index.ts
+ .gitignore
+ tsconfig.json (for editor auto-complete)
+ README.md
To get started, run:
bun run index.ts
Since the entry point is a *.ts
file, Bun generates a tsconfig.json
for you. If you’re using plain JavaScript, it will generate a jsconfig.json
instead.
Run a file
Open index.ts
and paste the following code snippet, which implements a simple HTTP server with Bun.serve
.
const server = Bun.serve({
port: 3000,
fetch(req) {
return new Response(`Bun!`);
},
});
console.log(`Listening on http://localhost:${server.port} ...`);
Run the file from your shell.
bun index.ts
Listening at http://localhost:3000 …
Visit http://localhost:3000 to test the server. You should see a simple page that says “Bun!”.
Run a script
Bun can also execute "scripts"
from your package.json
. Add the following script:
{
"name": "quickstart",
"module": "index.ts",
"type": "module",
"scripts": {
"start": "bun run index.ts"
},
"devDependencies": {
"bun-types": "^0.7.0"
}
}
Then run it with bun run start
.
bun run start
$ bun run index.ts
Listening on http://localhost:4000…
⚡️ Performance — bun run
is roughly 28x faster than npm run
(6ms vs 170ms of overhead).
Install a Package
Let’s make our server a little more interesting by installing a package. First install the figlet
package and its type declarations. Figlet is a utility for converting strings into ASCII art.
bun add figlet
bun add -d @types/figlet
Update index.ts
to use figlet
in the fetch
handler.
import figlet from "figlet";
const server = Bun.serve({
fetch() {
const body = figlet.textSync('Bun!');
return new Response(body);
return new Response(`Bun!`);
},
port: 3000,
});
Restart the server and refresh the page. You should see a new ASCII art banner.
____ _
| __ ) _ _ _ __ | |
| _ | | | | '_ | |
| |_) | |_| | | | |_|
|____/ __,_|_| |_(_)
That’s it!
License
JavaScriptCore
Bun statically links JavaScriptCore (and WebKit) which is LGPL-2 licensed. WebCore files from WebKit are also licensed under LGPL2. Per LGPL2:
(1) If you statically link against an LGPL’d library, you must also provide your application in an object (not necessarily source) format, so that a user has the opportunity to modify the library and relink the application.
You can find the patched version of WebKit used by Bun here: https://github.com/oven-sh/webkit. If you would like to relink Bun with changes:
git submodule update --init --recursive
make jsc
zig build
This compiles JavaScriptCore, compiles Bun’s .cpp
bindings for JavaScriptCore (which are the object files using JavaScriptCore) and outputs a new bun
binary with your changes.
Linked libraries
Bun statically links these libraries:
Library | License |
---|---|
boringssl | several licenses |
libarchive | several licenses |
lol-html | BSD 3-Clause |
mimalloc | MIT |
picohttp | dual-licensed under the Perl License or the MIT License |
zstd | dual-licensed under the BSD License or GPLv2 license |
simdutf | Apache 2.0 |
tinycc | LGPL v2.1 |
uSockets | Apache 2.0 |
zlib-cloudflare | zlib |
c-ares | MIT licensed |
libicu 72 | license here |
libbase64 | BSD 2-Clause |
A fork of uWebsockets | Apache 2.0 licensed |
Parts of Tigerbeetle’s IO code | Apache 2.0 licensed |
Polyfills
For compatibility reasons, the following packages are embedded into Bun’s binary and injected if imported.
Package | License |
---|---|
assert | MIT |
browserify-zlib | MIT |
buffer | MIT |
constants-browserify | MIT |
crypto-browserify | MIT |
domain-browser | MIT |
events | MIT |
https-browserify | MIT |
os-browserify | MIT |
path-browserify | MIT |
process | MIT |
punycode | MIT |
querystring-es3 | MIT |
stream-browserify | MIT |
stream-http | MIT |
string_decoder | MIT |
timers-browserify | MIT |
tty-browserify | MIT |
url | MIT |
util | MIT |
vm-browserify | MIT |
Be the first to comment