Bun is a modern JavaScript runtime designed to be fast, all-in-one, and compatible with Node.js. Built in Zig and running JavaScriptCore engine, Bun aims to be the fastest way to run JavaScript. This comprehensive guide covers everything you need to know about Bun.
What is Bun?
Bun is an all-in-one JavaScript runtime created by Jarred Sumner that includes:
- Runtime - Execute JavaScript and TypeScript
- Package Manager - Fast npm alternative
- Test Runner - Built-in testing framework
- Bundler - Fast build tool
- Script Runner - Execute .js, .ts, .mjs files
# Install Bun
curl -fsSL https://bun.sh/install | bash
# Run a JavaScript file
bun run index.js
# Run a TypeScript file
bun run index.ts
# Install dependencies
bun install
# Run tests
bun test
# Build for production
bun build
Why Bun is Fast
Bun achieves exceptional performance through several architectural decisions:
graph TB
subgraph Bun["Bun Architecture"]
JS["JavaScriptCore Engine"] --> BunRT["Bun Runtime"]
BunRT --> Z["Zig Runtime"]
Z --> F["Fast I/O"]
B["Built-in Tools"] --> P["Package Manager"]
B --> T["Test Runner"]
B --> Bu["Bundler"]
JS --> S["Startup Time: <10ms"]
JS --> E["~3x faster than Node.js"]
end
Performance Benchmarks
| Operation | Bun | Node.js | Deno |
|---|---|---|---|
| HTTP Server | ~45K req/s | ~15K req/s | ~12K req/s |
| Package install | ~3s | ~45s | ~20s |
| TypeScript startup | ~20ms | ~200ms | ~150ms |
| File system ops | 3-5x faster | Baseline | 1.5x faster |
Installation and Setup
Installing Bun
# macOS/Linux (via curl)
curl -fsSL https://bun.sh/install | bash
# Windows (via PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"
# Via npm
npm install -g bun
# Via Homebrew
brew install oven-sh/bun/bun
# Via Docker
docker pull oven/bun
Verify Installation
bun --version
# Output: Bun v1.x.x
Using Bun as Runtime
Running Scripts
// hello.js
console.log("Hello from Bun!");
// Run with Bun
bun run hello.js
// Run with shebang
#!/usr/bin/env bun
console.log("Direct execution!");
// app.ts
interface User {
name: string;
age: number;
}
const user: User = { name: "Alice", age: 30 };
console.log(`User: ${user.name}, Age: ${user.age}`);
HTTP Server
// server.ts
const server = Bun.serve({
port: 3000,
fetch(req) {
return new Response("Hello from Bun!", {
headers: { "Content-Type": "text/plain" }
});
}
});
console.log(`Server running at http://localhost:${server.port}`);
// Express-style server
import { Express } from "express";
const app = new Express();
app.get("/", (req, res) => {
res.json({ message: "Hello from Bun!" });
});
app.listen(3000, () => {
console.log("Express on Bun!");
});
File Operations
// Read file
const content = await Bun.file("package.json").text();
// Read as JSON
const pkg = await Bun.file("package.json").json();
// Write file
await Bun.write("output.txt", "Hello World");
// File exists check
const exists = await Bun.file("test.txt").exists();
TCP Server
// TCP echo server
const server = Bun.listen({
port: 3000,
socket: {
open(socket) {
console.log("Client connected");
},
data(socket, data) {
socket.write(data); // Echo back
},
close(socket) {
console.log("Client disconnected");
},
error(socket, error) {
console.error("Error:", error);
}
}
});
Bun Package Manager
Installing Dependencies
# Install all dependencies from package.json
bun install
# Install a package
bun add react
bun add -d typescript
# Remove a package
bun remove react
# Update packages
bun update
# Add with version
bun add react@18
bun add lodash@^4.0.0
Bun.lockb
Bun uses bun.lockb instead of package-lock.json or yarn.lock:
# Works with npm packages
bun add express
# Works with GitHub repos
bun add jarred/argon2
# Works with local packages
bun add link:/path/to/local/package
workspace Support
{
"name": "my-monorepo",
"workspaces": ["packages/*"]
}
Bun Test Runner
Writing Tests
import { test, expect, describe } from "bun:test";
describe("Math utilities", () => {
test("adds numbers", () => {
expect(1 + 1).toBe(2);
});
test("arrays", () => {
const arr = [1, 2, 3];
expect(arr).toContain(2);
expect(arr).toHaveLength(3);
});
});
test("async operation", async () => {
const result = await Promise.resolve(42);
expect(result).toBe(42);
});
Running Tests
# Run all tests
bun test
# Run specific file
bun test my.test.ts
# Run with coverage
bun test --coverage
# Watch mode
bun test --watch
Matchers Available
// Common matchers
expect(value).toBe(expected)
expect(value).toEqual(expected)
expect(value).toBeNull()
expect(value).toBeUndefined()
expect(value).toBeTruthy()
expect(value).toBeFalsy()
expect(value).toContain(item)
expect(value).toHaveLength(n)
expect(value).toThrow()
expect(promise).resolves.toBe(expected)
expect(promise).rejects.toThrow()
Bun Bundler
Building for Production
# Bundle for browser
bun build ./src/index.ts --outdir ./dist --target browser
# Bundle for Node.js
bun build ./src/index.ts --outdir ./dist --target node
# Create executable
bun build ./src/index.ts --compile --outfile myapp
Bun.build API
const result = await Bun.build({
entries: ["./src/index.ts"],
outdir: "./dist",
target: "browser",
minify: true,
splitting: true,
sourcemap: "linked",
});
console.log(result.success);
Environment Variables
.env Support
# .env file
DATABASE_URL=postgres://localhost:5432/mydb
API_KEY=secret123
// Automatic .env loading
console.log(process.env.DATABASE_URL);
// Explicit .env
import { load } from "bun";
await load({ path: ".env.local" });
Working with TypeScript
tsconfig.json Support
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true
}
}
Bun automatically handles TypeScript with no extra config needed:
// Direct TypeScript execution
bun run app.ts
// Type checking
bun run --bun-typecheck app.ts
// TSX support (TypeScript + JSX)
bun run component.tsx
Database Integration
SQLite with Bun
import { Database } from "bun:sqlite";
const db = new Database("app.db");
// Create table
db.exec(`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT
)
`);
// Insert
const insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
insert.run("Alice", "[email protected]");
// Query
const users = db.query("SELECT * FROM users").all();
console.log(users);
Using with ORMs
// Prisma with Bun
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
const users = await prisma.user.findMany();
console.log(users);
Bun vs Node.js vs Deno
| Feature | Bun | Node.js | Deno |
|---|---|---|---|
| Engine | JavaScriptCore | V8 | V8 |
| Language | Zig | C++ | Rust |
| Package Manager | Built-in | npm | npm-compatible |
| TypeScript | Native | Via transpiler | Native |
| Top-level await | Yes | Yes (ES modules) | Yes |
| ES Modules | Default | CommonJS default | ESM default |
| Fetch API | Native | Native | Native |
| Web Streams | Native | Native | Native |
| SQLite | Built-in | Via package | Via package |
Migration Guide
// Node.js
const fs = require("fs");
const path = require("path");
module.exports = {};
// Bun (uses ES modules)
import { readFile, resolve } from "fs";
import path from "path";
export const foo = "bar";
// CommonJS in Bun (still works)
const fs = require("fs");
Common Issues and Solutions
“Cannot find module”
# Clear bun's cache
bun pm cache rm
# Reinstall
bun install
Version Conflicts
# Check Bun version
bun --version
# Update Bun
bun upgrade
Platform Support
// Check platform
console.log(process.platform); // "darwin" | "linux" | "windows"
console.log(process.arch); // "x64" | "arm64"
Production Deployment
Docker
FROM oven/bun:1 AS builder
WORKDIR /app
COPY . .
RUN bun install --production
FROM oven/bun:1-alpine
WORKDIR /app
COPY --from=builder /app/node_modules node_modules
COPY . .
EXPOSE 3000
CMD ["bun", "src/index.ts"]
Serverless
// Cloudflare Workers
export default {
fetch(request) {
return new Response("Hello from Bun!");
}
};
Process Management
# Production running
bun --hot reload app.ts # Hot reload (dev)
bun run --production app.ts # Production
# With process manager
bun add -d pm2
pm2 start app.ts
When to Use Bun
Good Use Cases
- Fast development - Quick startup, hot reload
- Simple projects - No build step needed
- Scripting - TypeScript without setup
- APIs - Fast HTTP servers
- Monorepos - Fast package management
- Edge deployment - Small bundle sizes
When to Avoid
- Production critical apps - Still maturing
- Native Node modules - Some packages may not work
- Complex build requirements - Use webpack/vite for advanced bundling
- Windows server - Linux/macOS support is better
Comments