Bun Runtime Cheat Sheet
Bun's built-in APIs for HTTP servers, file I/O, bundling, testing, and package management as a fast Node.js-compatible runtime.
CLI Essentials
Bun replaces node, npm, jest, and webpack/esbuild with one binary.
bun install # install deps (reads package.json, writes bun.lockb)bun add zod # add a dependencybun run dev # run a package.json scriptbun index.ts # run a TS/JS file directly, no build stepbun test # run the built-in test runnerbun build ./index.ts --outdir ./dist --target browserbun --hot server.ts # hot-reload a running server
Bun.serve HTTP Server
Zero-dependency, high-throughput HTTP server built into the runtime.
const server = Bun.serve({ port: 3000, fetch(req) { const url = new URL(req.url) if (url.pathname === "/") return new Response("Hello Bun!") if (url.pathname === "/json") { return Response.json({ ok: true }) } return new Response("Not Found", { status: 404 }) }, error(err) { return new Response(`Error: ${err.message}`, { status: 500 }) },})console.log(`Listening on http://localhost:${server.port}`)
Fast File I/O
Bun.file/Bun.write avoid Node's fs callback ceremony for common cases.
const file = Bun.file("data.json")const exists = await file.exists()const text = await file.text()const json = await file.json()await Bun.write("out.txt", "hello world")await Bun.write("copy.json", Bun.file("data.json")) // fast file copy// streamingconst stream = file.stream()
Built-in Test Runner
Jest-compatible API, no separate test framework install needed.
import { test, expect, describe, mock } from "bun:test"describe("add", () => { test("adds two numbers", () => { expect(1 + 2).toBe(3) }) test("mocked fetch", () => { const fetchMock = mock(() => Promise.resolve({ ok: true })) expect(fetchMock).not.toHaveBeenCalled() })})// run: bun test --coverage
Bun-Specific Globals & APIs
Runtime APIs that don't exist in plain Node.
- Bun.serve()- built-in HTTP/WebSocket server, faster than express on raw throughput
- Bun.file() / Bun.write()- lazy file references with a Blob-like read API
- Bun.$ (Shell)- tagged template for running shell commands cross-platform: `await $\`ls -la\``
- Bun.SQLite- built-in synchronous SQLite driver, no native module install
- bun:test- Jest-compatible test runner built into the binary
- bunfig.toml- project-level runtime/bundler configuration file
Bun.$ Shell Scripting
Bun.$ runs real shell pipelines cross-platform (including Windows) and captures output as text, JSON, or a Buffer.
import { $ } from "bun"const branch = (await $`git rev-parse --abbrev-ref HEAD`.text()).trim()await $`rm -rf dist && mkdir dist`await $`cp -r src/assets dist/assets`// pipe and capture JSON safely, values are auto-escapedconst pkgName = "lodash"const info = await $`npm view ${pkgName} --json`.json()// non-zero exit throws by default; opt out with .nothrow()const result = await $`test -f ./missing.txt`.nothrow()console.log(result.exitCode)
bun:sqlite Driver
Synchronous, embedded SQLite access with prepared statements, no native module compilation required.
import { Database } from "bun:sqlite"const db = new Database("app.db", { create: true })db.run("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")const insert = db.prepare("INSERT INTO users (name) VALUES (?)")insert.run("Ana")const getAll = db.query("SELECT * FROM users")console.log(getAll.all()) // [{ id: 1, name: 'Ana' }]db.transaction(() => { insert.run("Ben") insert.run("Cid")})()
WebSockets via Bun.serve
Bun.serve natively multiplexes HTTP and WebSocket upgrades on the same server, with pub/sub topics built in.
Bun.serve({ port: 3000, fetch(req, server) { if (server.upgrade(req)) return // response handled by websocket handlers return new Response("Upgrade failed", { status: 500 }) }, websocket: { open(ws) { ws.subscribe("chat") }, message(ws, message) { ws.publish("chat", `peer: ${message}`) }, close(ws) { ws.unsubscribe("chat") }, },})
bun:ffi for Native Libraries
Call C ABI-compatible shared libraries directly from JS with dlopen, similar in spirit to Deno's FFI.
import { dlopen, FFIType, suffix } from "bun:ffi"const { symbols: { add } } = dlopen(`libadd.${suffix}`, { add: { args: [FFIType.i32, FFIType.i32], returns: FFIType.i32 },})console.log(add(2, 3)) // 5
Bundler & Runtime Performance Flags
Flags and config for squeezing startup and bundle size.
- bun build --minify --splitting- minify output and enable code-splitting for shared chunks
- bun build --target=bun- emit output optimized to run under the Bun runtime itself (server code)
- --smol- reduce memory usage at some throughput cost, useful in constrained containers
- bun run --bun <script>- force a package.json script to execute under Bun even if it shebangs node
- Bun.gc(true)- force a synchronous GC pass, useful when profiling memory in dev
- bunfig.toml [install] exact = true- pin exact dependency versions instead of caret ranges by default
Bun is Node-API compatible for most packages, but native Node addons relying on obscure `node:` internals can still break — run `bun test` and your CI matrix against Bun before fully dropping Node from production, especially for anything using worker_threads or crypto edge cases.