Loading

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

Source Code

$ 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…

⚡️ Performancebun 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:

LibraryLicense
boringsslseveral licenses
libarchiveseveral licenses
lol-htmlBSD 3-Clause
mimallocMIT
picohttpdual-licensed under the Perl License or the MIT License
zstddual-licensed under the BSD License or GPLv2 license
simdutfApache 2.0
tinyccLGPL v2.1
uSocketsApache 2.0
zlib-cloudflarezlib
c-aresMIT licensed
libicu 72license here
libbase64BSD 2-Clause
A fork of uWebsocketsApache 2.0 licensed
Parts of Tigerbeetle’s IO codeApache 2.0 licensed

Polyfills

For compatibility reasons, the following packages are embedded into Bun’s binary and injected if imported.

PackageLicense
assertMIT
browserify-zlibMIT
bufferMIT
constants-browserifyMIT
crypto-browserifyMIT
domain-browserMIT
eventsMIT
https-browserifyMIT
os-browserifyMIT
path-browserifyMIT
processMIT
punycodeMIT
querystring-es3MIT
stream-browserifyMIT
stream-httpMIT
string_decoderMIT
timers-browserifyMIT
tty-browserifyMIT
urlMIT
utilMIT
vm-browserifyMIT

Additional credits

  • Bun’s JS transpiler, CSS lexer, and Node.js module resolver source code is a Zig port of @evanw’s esbuild project.
  • Credit to @kipply for the name “Bun”!