# Bun — User Guide

> [!TIP]
> Bun is your all-in-one JavaScript toolkit: runtime, package manager, bundler, and test runner in a single binary. If you're coming from Node.js, drop Bun in and gain dramatically faster installs and startup times with zero config changes.

---

## 1. Quick Start

Bun is a fast, all-in-one JavaScript runtime built with performance as a first principle. It runs JavaScript, TypeScript, JSX, and TSX natively without any additional tooling. The package manager installs dependencies up to 25× faster than npm. The bundler replaces webpack and esbuild. The test runner is Jest-compatible. SQLite, PostgreSQL, MySQL, Redis, and S3 clients ship built-in. Shell scripting works via `Bun.$`. And `bun build --compile` produces self-contained executables.

**Prerequisites:**

- macOS (arm64 or x64), Linux (arm64 or x64, glibc or musl), or Windows (x64 or arm64)
- No Node.js required — Bun is self-contained

**Install in one line:**

```bash
curl -fsSL https://bun.sh/install | bash
```

**Your first project:**

```bash
mkdir my-app && cd my-app
bun init
bun run index.ts
```

`bun init` scaffolds a minimal TypeScript project with `package.json`, `tsconfig.json`, `index.ts`, `.gitignore`, and `README.md`. `bun run index.ts` executes it immediately — no compile step, no `ts-node`, no separate transpiler.

**Expected output from `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 (my-app):
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
```

**Verify your installation:**

```bash
bun --version
# 1.3.13
```

> [!NOTE]
> Bun reads `tsconfig.json` for path aliases and JSX settings automatically. You don't need any additional TypeScript configuration to run `.ts` files.

---

## 2. Installation

### Supported Platforms

| Platform | Architecture | Notes |
|---|---|---|
| macOS | arm64 (Apple Silicon) | Primary development platform |
| macOS | x64 (Intel) | Fully supported |
| Linux | arm64 | glibc and musl |
| Linux | x64 | glibc and musl |
| Windows | x64 | Full support |
| Windows | arm64 | Full support |

### Installation Methods

#### curl (macOS and Linux — recommended)

```bash
curl -fsSL https://bun.sh/install | bash
```

After install, restart your terminal or run `source ~/.bashrc` (or `~/.zshrc`). The installer adds Bun to `~/.bun/bin` and updates your shell's PATH.

#### npm

```bash
npm install -g bun
```

Useful if you already have Node.js and want a quick install without running a shell script.

#### Homebrew (macOS and Linux)

```bash
brew tap oven-sh/bun
brew install oven-sh/bun/bun
```

#### Docker

```bash
docker pull oven/bun:latest
```

Available image variants:

| Tag | Base | Use Case |
|---|---|---|
| `oven/bun:latest` | Debian | General purpose |
| `oven/bun:alpine` | Alpine | Minimal image size |
| `oven/bun:debian` | Debian | Explicit Debian |
| `oven/bun:debian-slim` | Debian Slim | Smaller Debian footprint |
| `oven/bun:distroless` | Distroless | Production security hardening |

Example `Dockerfile`:

```dockerfile
FROM oven/bun:latest
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
COPY . .
CMD ["bun", "run", "src/index.ts"]
```

#### Scoop (Windows)

```bash
scoop install bun
```

#### Proto (version manager)

```bash
proto install bun
```

### CPUs Without AVX2 Support

Older CPUs that lack AVX2 instructions require the baseline build:

```bash
curl -fsSL https://bun.sh/install | bash -s -- --no-avx2
```

> [!IMPORTANT]
> If Bun crashes immediately with an illegal instruction error on startup, your CPU likely lacks AVX2 support. Reinstall using the `--no-avx2` flag above.

### Upgrading Bun

```bash
bun upgrade
```

This downloads the latest release directly from GitHub. To upgrade to a specific version:

```bash
bun upgrade --version 1.3.13
```

To upgrade to the canary (nightly) build:

```bash
bun upgrade --canary
```

---

## 3. Configuration

### bunfig.toml

`bunfig.toml` is Bun's primary configuration file. It can live at the project root (per-project) or at `~/.bunfig.toml` (global user defaults). Project-level settings override global ones.

```toml
[install]
# Do not install devDependencies
production = false

# Fail if bun.lockb would change (useful in CI)
frozen-lockfile = false

# Default registry
registry = "https://registry.npmjs.org/"

# Default installation backend
# Options: clonefile (default on macOS), hardlink, symlink, copyfile
# backend = "clonefile"

[run]
# Shell used to run package.json scripts
# "bun" = Bun's built-in shell (cross-platform)
# "system" = /bin/sh on Unix, cmd.exe on Windows
shell = "bun"

[test]
# Per-test timeout in milliseconds
timeout = 5000

# Collect coverage by default
coverage = false

# Coverage reporters: "text", "lcov"
coverageReporter = ["text"]

# Directory for coverage output
# coverageDir = "coverage"
```

Bun also reads `tsconfig.json` for:
- **Path aliases** (`compilerOptions.paths`) — resolved automatically at runtime
- **JSX settings** (`compilerOptions.jsx`, `jsxImportSource`) — no build step needed

### Environment Variables

Bun automatically loads `.env` files at startup in this priority order:

1. `.env.local`
2. `.env.development` (or `.env.production` when `NODE_ENV=production`)
3. `.env`

Access them via `process.env` or `Bun.env`:

```typescript
// index.ts
console.log(process.env.DATABASE_URL);
console.log(Bun.env.DATABASE_URL); // same thing
```

**Custom env file:**

```bash
bun run --env-file .env.staging server.ts
```

**Disable env file loading entirely:**

```bash
bun run --no-env-file server.ts
```

> [!TIP]
> Bun supports multiple `--env-file` flags in a single command, loaded in order. Later files take precedence for duplicate keys.

### Per-Registry Authentication (bunfig.toml)

```toml
[install.scopes]
"@myorg" = { token = "$NPM_TOKEN", registry = "https://npm.pkg.github.com/" }
```

For private registries requiring auth, set credentials per scope rather than globally to avoid leaking tokens.

---

## 4. Core Usage

### Running Scripts

#### Run a file directly

```bash
bun run index.ts
bun index.ts          # shorthand — same result
```

TypeScript, JSX, and TSX work without any configuration:

```bash
bun run app.tsx
bun run utils.js
bun run server.mjs
```

#### Run package.json scripts

```bash
bun run dev
bun run build
bun run test
```

> [!NOTE]
> `bun run` is significantly faster at script lookup and startup than `npm run`. For a project with dozens of scripts, the difference is immediately noticeable.

#### Watch mode (restart on change)

```bash
bun run --watch index.ts
```

Bun watches the entry file and all imported modules. The process restarts cleanly on any change.

#### Hot reload (preserve state)

```bash
bun run --hot server.ts
```

Hot reload re-evaluates changed modules without restarting the process. HTTP servers stay up; in-memory state is preserved. Ideal for server development where you don't want to drop connections.

**Difference between `--watch` and `--hot`:**

| Mode | Process Restart | State Preserved | Best For |
|---|---|---|---|
| `--watch` | Yes | No | Scripts, CLIs, workers |
| `--hot` | No | Yes | HTTP servers, long-running services |

#### Evaluate inline code

```bash
bun --eval 'console.log("hello")'
bun -e 'console.log(process.version)'

# Print the result of an expression
bun --print 'Math.PI * 2'
bun -p '["a","b","c"].join(",")'
```

#### Run scripts in workspaces

```bash
# Run "build" in all workspaces matching the pattern
bun run --filter "packages/*" build

# Run in parallel (default behavior with --filter)
bun run --filter "*" test --parallel

# Run sequentially
bun run --filter "*" build --sequential
```

### Package Management

#### Install all dependencies

```bash
bun install
bun i          # alias
```

Key flags:

| Flag | Purpose |
|---|---|
| `--production` / `-p` | Skip devDependencies |
| `--frozen-lockfile` | Fail if lockfile would change (CI recommended) |
| `--dry-run` | Show what would be installed without installing |
| `--force` / `-f` | Re-download packages even if cached |
| `--no-cache` | Ignore cache entirely |
| `--global` / `-g` | Install to global package store |
| `--save-text-lockfile` | Save `bun.lock` (text) instead of `bun.lockb` (binary) |
| `--backend <mode>` | `clonefile` (default macOS), `hardlink`, `symlink`, `copyfile` |
| `--linker <mode>` | `isolated` (default) or `hoisted` (node_modules flat layout) |
| `--omit <type>` | Omit `dev`, `optional`, or `peer` deps |
| `--lockfile-only` | Only update lockfile, do not install to node_modules |
| `--trust` | Mark installed packages as trusted (for lifecycle scripts) |
| `--analyze` / `-a` | Show bundle size analysis after install |

#### Add a dependency

```bash
bun add react react-dom
bun add --dev typescript @types/node   # devDependency
bun add --optional sharp               # optionalDependency
bun add --peer react                   # peerDependency
bun add --exact react                  # pin to exact version (no ^)
bun add --only-missing react           # add only if not already present
bun a zod                              # alias for add
```

#### Remove a dependency

```bash
bun remove react
bun rm react     # alias
```

#### Update dependencies

```bash
bun update                 # update within semver ranges
bun update --latest        # update to latest, ignoring semver ranges
bun update --interactive   # choose per package interactively
bun update --recursive     # update across all workspaces
```

#### Check for outdated packages

```bash
bun outdated
bun outdated --filter "packages/ui"   # limit to a workspace
bun outdated --recursive              # check all workspaces
```

**Example output:**

```
Package   Current  Update  Latest
react     18.2.0   18.3.1  19.0.0
```

#### Security audit

```bash
bun audit          # human-readable output
bun audit --json   # machine-readable JSON
```

#### Run packages without installing

```bash
bunx cowsay "hello"
bun x cowsay "hello"   # alias

# Force running with Bun (instead of Node.js shebang)
bunx --bun tsx script.ts
```

`bunx` downloads and caches the package, then runs it. The cache persists across invocations so subsequent runs are instant.

#### Link local packages

```bash
# In the package you want to link
bun link

# In the project that should use it
bun link my-local-package
```

### Bundling

#### Basic bundle

```bash
bun build src/index.ts --outdir dist
```

#### Target environments

```bash
bun build src/index.ts --outdir dist --target browser   # browser bundle
bun build src/index.ts --outdir dist --target bun       # Bun runtime
bun build src/index.ts --outdir dist --target node      # Node.js runtime
```

#### Output formats

```bash
bun build src/index.ts --outfile bundle.js --format esm    # ES modules (default)
bun build src/index.ts --outfile bundle.js --format cjs    # CommonJS
bun build src/index.ts --outfile bundle.js --format iife   # IIFE for <script> tags
```

#### Code splitting

```bash
bun build src/index.ts --outdir dist --splitting
```

Produces multiple chunks that share code; useful for browser apps with dynamic imports.

#### Source maps

```bash
bun build src/index.ts --outdir dist --sourcemap linked    # separate .map file, linked
bun build src/index.ts --outdir dist --sourcemap inline    # embedded in output
bun build src/index.ts --outdir dist --sourcemap external  # separate .map, not linked
bun build src/index.ts --outdir dist --sourcemap none      # disabled
```

#### Minification

```bash
bun build src/index.ts --outdir dist --minify                    # all minification
bun build src/index.ts --outdir dist --minify-syntax             # fold constants, simplify
bun build src/index.ts --outdir dist --minify-whitespace         # remove whitespace
bun build src/index.ts --outdir dist --minify-identifiers        # shorten variable names
```

#### Compile a standalone executable

```bash
bun build src/cli.ts --compile --outfile my-tool
./my-tool   # runs without Bun installed
```

The resulting binary bundles the Bun runtime and your code. No external dependencies required on the target machine.

**Windows executable options:**

```bash
bun build src/app.ts --compile --outfile app.exe \
  --windows-hide-console \
  --windows-icon assets/icon.ico \
  --windows-title "My App" \
  --windows-publisher "Acme Corp" \
  --windows-version "1.0.0" \
  --windows-description "Does something useful" \
  --windows-copyright "Copyright 2026"
```

**Compile-time autoload control:**

```bash
# Disable .env autoloading in the compiled binary
bun build src/app.ts --compile --no-compile-autoload-dotenv

# Control other autoloaded files
bun build src/app.ts --compile \
  --no-compile-autoload-bunfig \
  --no-compile-autoload-tsconfig \
  --no-compile-autoload-package-json
```

#### Other build flags

| Flag | Purpose |
|---|---|
| `--external <pkg>` | Exclude package from bundle (treated as external) |
| `--watch` | Rebuild on file changes |
| `--metafile` | Emit `metafile.json` with bundle analysis |
| `--metafile-md` | Emit `metafile.md` (human-readable analysis) |
| `--banner <text>` | Prepend text to output files |
| `--footer <text>` | Append text to output files |
| `--public-path <url>` | URL prefix for asset references |
| `--packages <mode>` | `external` (exclude all npm) or `bundle` (include all) |
| `--env <mode>` | `inline` (embed env), `prefix*` (embed matching), `disable` |
| `--production` | Set `NODE_ENV=production` and enable full minification |
| `--no-bundle` | Transpile only — no bundling, preserves imports |
| `--keep-names` | Preserve function/class names after minification |
| `--bytecode` | Emit bytecode alongside JS for faster cold starts |
| `--define` / `-d` | Replace identifiers at build time |
| `--loader` / `-l` | Override file loader (e.g., `.png:dataurl`) |

**Experimental:**

```bash
# Bun Bake — full-stack web app bundler (experimental)
bun build --app

# Server Components (experimental)
bun build --app --server-components
```

### Testing

#### Run all tests

```bash
bun test
```

Bun discovers test files matching `**/*.test.{ts,tsx,js,jsx}`, `**/*.spec.{ts,tsx,js,jsx}`, and `**/test.{ts,js}`.

#### Filter tests

```bash
bun test --test-name-pattern "auth"        # run tests matching regex
bun test -t "should handle errors"         # same, short flag
bun test src/auth.test.ts                  # run specific file
```

#### Test options

| Flag | Purpose |
|---|---|
| `--timeout <ms>` | Per-test timeout (default 5000) |
| `--update-snapshots` / `-u` | Overwrite snapshot files |
| `--bail <n>` | Stop after n failures |
| `--only` | Run only tests marked `test.only()` |
| `--todo` | Run tests marked `test.todo()` |
| `--rerun-each <n>` | Run each test n times (for flakiness detection) |
| `--retry <n>` | Retry failing tests up to n times |
| `--randomize` | Randomize test order |
| `--seed <int>` | Set random seed for reproducible randomization |
| `--pass-with-no-tests` | Exit 0 when no test files found |
| `--concurrent` | Run test files concurrently |
| `--max-concurrency <n>` | Limit concurrent test file execution |
| `--dots` | Minimal dot-style reporter |
| `--reporter <mode>` | `junit` or `dots` |
| `--reporter-outfile <path>` | Write reporter output to file |
| `--only-failures` | Re-run only previously failing tests |
| `--changed <ref>` | Run tests for files changed since git ref |
| `--path-ignore-patterns <glob>` | Exclude matching paths |

#### Coverage

```bash
bun test --coverage
bun test --coverage --coverage-reporter lcov
bun test --coverage --coverage-dir coverage/
```

**Example output with coverage:**

```
✓ src/math.test.ts > add > handles integers [0.42ms]
✓ src/math.test.ts > add > handles floats [0.12ms]
✓ src/math.test.ts > multiply > basic multiplication [0.08ms]

3 pass, 0 fail

Coverage report:
---------------------|---------|----------|---------|---------|
File                 | % Stmts | % Branch | % Funcs | % Lines |
---------------------|---------|----------|---------|---------|
src/math.ts          |   100   |    100   |   100   |   100   |
---------------------|---------|----------|---------|---------|
```

#### Writing tests (Jest-compatible API)

```typescript
import { describe, it, expect, beforeEach, afterAll, mock, spyOn } from "bun:test";

describe("UserService", () => {
  let service: UserService;

  beforeEach(() => {
    service = new UserService();
  });

  it("creates a user", async () => {
    const user = await service.create({ name: "Alice" });
    expect(user.id).toBeDefined();
    expect(user.name).toBe("Alice");
  });

  it("throws on duplicate email", () => {
    expect(() => service.create({ email: "[email removed]" })).toThrow();
  });
});
```

Bun's test runner supports: `describe`, `it`, `test`, `expect`, `beforeAll`, `afterAll`, `beforeEach`, `afterEach`, `mock`, `spyOn`, `jest.fn()`, `jest.mock()`, snapshot testing, and `test.skip()` / `test.only()` / `test.todo()`.

### Other Commands

| Command | Purpose |
|---|---|
| `bun init` | Scaffold a new project |
| `bun repl` | Start an interactive JavaScript REPL |
| `bun exec <script>` | Execute a shell script file |
| `bun upgrade` | Upgrade Bun to the latest version |
| `bun pm` | Package manager utilities (cache, bin paths, etc.) |
| `bun pm cache` | Manage the package cache |
| `bun pm bin` | Show path to local bin directory |
| `bun pm ls` | List installed packages |
| `bun pm trust` | Manage trusted packages for lifecycle scripts |

### Global Runtime Flags

These flags work with `bun run`, `bun test`, `bun build`, and direct file execution:

| Flag | Purpose |
|---|---|
| `--env-file <path>` | Load environment variables from a specific file |
| `--no-env-file` | Disable automatic .env loading |
| `--cwd <path>` | Set working directory |
| `--config` / `-c <path>` | Use a specific bunfig.toml |
| `--watch` | Restart on file changes |
| `--hot` | Hot reload (preserve state) |
| `--smol` | Reduce memory usage (slower GC tradeoff) |
| `--preload <file>` / `-r` | Run a file before the entry point |
| `--inspect` | Enable debugger (default: `ws://localhost:6499`) |
| `--inspect-wait` | Enable debugger and wait for connection before starting |
| `--inspect-brk` | Enable debugger and pause on first line |
| `--cpu-prof*` | CPU profiling options |
| `--heap-prof*` | Heap profiling options |
| `--if-present` | Exit 0 if script not found in package.json |
| `--no-install` | Never auto-install missing modules |
| `--install <mode>` | `auto`, `fallback`, or `force` module resolution |
| `--port <n>` | Default HTTP port |
| `--conditions <list>` | Export condition overrides |
| `--no-macros` | Disable Bun macros |
| `--prefer-offline` | Use cache over network |
| `--prefer-latest` | Prefer latest version when resolving |
| `--max-http-header-size <n>` | Max HTTP header size in bytes |
| `--dns-result-order <mode>` | DNS result ordering (ipv4first, verbatim) |
| `--expose-gc` | Expose `global.gc()` |
| `--define` / `-d <k=v>` | Replace global identifiers |
| `--drop <identifier>` | Remove identifier references from code |
| `--loader` / `-l <ext:type>` | Override file loader |
| `--jsx-*` | JSX transform options |
| `--no-clear-screen` | Prevent clearing terminal in watch mode |
| `--unhandled-rejections <mode>` | `throw`, `warn`, `ignore` |
| `--console-depth <n>` | Max depth for `console.log` object inspection |
| `--title <name>` | Set process title |
| `--zero-fill-buffers` | Zero-fill `Buffer` allocations |
| `--use-system-ca` | Use system certificate store for TLS |
| `--use-openssl-ca` | Use OpenSSL certificate store |
| `--use-bundled-ca` | Use Bun's bundled CA certificates |
| `--redis-preconnect` | Open Redis connection at startup |
| `--sql-preconnect` | Open SQL connection at startup |

### Key Runtime APIs

#### HTTP Server

```typescript
import { serve } from "bun";

const server = Bun.serve({
  port: 3000,
  fetch(request) {
    const url = new URL(request.url);
    if (url.pathname === "/") {
      return new Response("Hello, Bun!", {
        headers: { "Content-Type": "text/plain" },
      });
    }
    return new Response("Not Found", { status: 404 });
  },
});

console.log(`Listening on http://localhost:${server.port}`);
```

#### File I/O

```typescript
// Read a file
const file = Bun.file("./data.json");
const data = await file.json();
const text = await Bun.file("./readme.txt").text();
const buffer = await Bun.file("./image.png").arrayBuffer();

// Check existence
const exists = await Bun.file("./config.yaml").exists();

// File stats
const stat = await Bun.file("./log.txt").stat();
console.log(stat.size, stat.mtime);

// Write a file
await Bun.write("./output.txt", "Hello, World!");
await Bun.write("./data.json", JSON.stringify({ key: "value" }, null, 2));

// Streaming write
const writer = Bun.file("./large.txt").writer();
writer.write("chunk 1\n");
writer.write("chunk 2\n");
await writer.end();

// Delete a file
await Bun.file("./temp.txt").delete();
```

#### Shell Scripting

```typescript
import { $ } from "bun";

// Run a command, get output
const result = await $`ls -la`.text();
console.log(result);

// Pipe between commands
const count = await $`cat package.json | wc -l`.text();

// Capture stderr separately
const { stdout, stderr } = await $`git status`.quiet();

// Use template literals with variables (safe — no injection)
const filename = "my file.txt";
await $`rm ${filename}`;

// Run in a specific directory
await $`npm install`.cwd("/tmp/my-project");
```

#### Database — PostgreSQL/MySQL

```typescript
import { sql } from "bun";

// Bun reads DATABASE_URL from environment
const users = await sql`SELECT * FROM users WHERE active = ${true}`;

// Transactions
await sql.transaction(async (tx) => {
  await tx`INSERT INTO orders (user_id, total) VALUES (${userId}, ${total})`;
  await tx`UPDATE users SET order_count = order_count + 1 WHERE id = ${userId}`;
});
```

#### Format Parsers

```typescript
// TOML
const config = Bun.TOML.parse(`[server]\nport = 3000`);

// YAML
const yaml = Bun.YAML.parse("name: bun\nversion: 1.3.13");
const yamlStr = Bun.YAML.stringify({ name: "bun" });

// JSONC (JSON with Comments)
const jsoncData = Bun.JSONC.parse(`{ // comment\n "key": "value" }`);

// JSON5
const json5 = Bun.JSON5.parse(`{ key: 'value', /* comment */ }`);
const json5Str = Bun.JSON5.stringify({ key: "value" });

// JSONL (JSON Lines)
const lines = Bun.JSONL.parse(`{"a":1}\n{"b":2}\n`);
// lines = [{ a: 1 }, { b: 2 }]
```

#### Markdown Rendering

```typescript
// Render to HTML
const html = Bun.markdown.html("# Hello\n\nThis is **bold**.");

// Render to ANSI terminal output
const terminal = Bun.markdown.ansi("# Hello\n\nThis is **bold**.");

// Render with options
const rendered = Bun.markdown.render("## Section\n\nContent.");

// Render to React elements
const reactEl = Bun.markdown.react("## Section");
```

#### Password Hashing

```typescript
// Hash a password (uses bcrypt by default)
const hash = await Bun.password.hash("my-secret-password");

// Verify
const isValid = await Bun.password.verify("my-secret-password", hash);
// true

// Explicit algorithm
const bcryptHash = await Bun.password.hash("password", { algorithm: "bcrypt", cost: 10 });
const argon2Hash = await Bun.password.hash("password", { algorithm: "argon2id" });
```

#### Non-Crypto Hashing

```typescript
// Fast hashing for hash tables, checksums
const hash1 = Bun.hash.wyhash("hello world");
const hash2 = Bun.hash.crc32("data");
const hash3 = Bun.hash.xxHash64("large data");
const hash4 = Bun.hash.murmur32("input");
const hash5 = Bun.hash.cityHash32("input");
```

#### Terminal String Utilities

```typescript
Bun.stringWidth("hello");        // 5 (handles unicode/emoji width)
Bun.stripANSI("\x1b[31mred\x1b[0m");  // "red"
Bun.sliceAnsi("\x1b[31mhello\x1b[0m", 0, 3);  // "\x1b[31mhel\x1b[0m"
Bun.wrapAnsi("long text...", 40);  // word-wrap preserving ANSI codes
```

#### CSRF Protection

```typescript
const token = Bun.CSRF.generate();
const isValid = Bun.CSRF.verify(token, storedToken);
```

#### Web Workers

```typescript
const worker = new Worker("./worker.ts", {
  smol: true,           // reduced memory mode
  preload: "./setup.ts", // run before worker code
  env: { API_URL: "https://api.example.com" }, // isolated env
});

worker.postMessage({ task: "compute", data: [1, 2, 3] });
worker.onmessage = (e) => console.log(e.data);
```

---

## 5. Common Tasks

### Create and Run a TypeScript Project

```bash
mkdir my-service && cd my-service
bun init -y
```

Edit `index.ts`:

```typescript
const greeting = (name: string): string => `Hello, ${name}!`;
console.log(greeting("Bun"));
```

```bash
bun run index.ts
# Hello, Bun!
```

No `tsc`, no `ts-node`, no build step.

### Set Up an HTTP Server

```typescript
// server.ts
Bun.serve({
  port: 3000,
  async fetch(req) {
    const url = new URL(req.url);

    if (req.method === "GET" && url.pathname === "/health") {
      return Response.json({ status: "ok", uptime: process.uptime() });
    }

    if (req.method === "POST" && url.pathname === "/echo") {
      const body = await req.json();
      return Response.json(body);
    }

    return new Response("Not Found", { status: 404 });
  },
});
```

```bash
bun run --hot server.ts
# Listening on http://localhost:3000
```

Modify `server.ts` and save — the server reloads without dropping connections.

### Install Packages and Manage Dependencies

```bash
# Add production dependencies
bun add express zod

# Add development dependencies
bun add --dev @types/express vitest

# Install all deps (e.g., after cloning a repo)
bun install

# Install for CI (fail if lockfile would change)
bun install --frozen-lockfile

# Install production only (skip devDeps)
bun install --production
```

Bun creates `bun.lockb` (binary lockfile) or `bun.lock` (text, with `--save-text-lockfile`). Commit either to version control for reproducible installs.

### Bundle for Production

```bash
# Browser bundle with minification
bun build src/index.ts \
  --outdir dist \
  --target browser \
  --minify \
  --sourcemap linked \
  --production

# Check what was emitted
ls dist/
# index.js  index.js.map  metafile.json
```

With code splitting for a multi-page app:

```bash
bun build src/pages/*.ts \
  --outdir dist \
  --target browser \
  --splitting \
  --format esm
```

### Create a Standalone Executable

```typescript
// cli.ts
const args = process.argv.slice(2);
if (args[0] === "--help") {
  console.log("Usage: my-tool [options]");
  process.exit(0);
}
console.log("Running with args:", args);
```

```bash
bun build cli.ts --compile --outfile my-tool

# Test it — no Bun needed on target machine
./my-tool --help
# Usage: my-tool [options]

# Check the binary
file my-tool
# my-tool: ELF 64-bit LSB executable, x86-64, ...
```

### Run Tests with Coverage

```bash
# Run all tests with coverage
bun test --coverage

# CI-friendly: fail if coverage drops below threshold, use lcov for reporting
bun test \
  --coverage \
  --coverage-reporter lcov \
  --coverage-dir coverage \
  --bail 1
```

Configure default coverage behavior in `bunfig.toml`:

```toml
[test]
coverage = true
coverageReporter = ["text", "lcov"]
coverageDir = "coverage"
```

### Use Hot Reloading During Development

```bash
# Start server with hot reload
bun run --hot src/server.ts

# In another terminal, watch your changes take effect live
curl http://localhost:3000/health
```

For scripts and CLIs where you want a clean restart:

```bash
bun run --watch src/worker.ts
```

### Parse Environment Variables from .env Files

```bash
# .env
DATABASE_URL=postgresql://localhost/mydb
PORT=3000
NODE_ENV=development
```

```typescript
// These are automatically available — no dotenv package needed
const db = Bun.env.DATABASE_URL;
const port = parseInt(Bun.env.PORT ?? "3000");
```

```bash
# Use a different env file
bun run --env-file .env.staging src/server.ts

# Disable env file loading
bun run --no-env-file src/server.ts
```

### Use Bun as a Drop-In Node.js Replacement

For most Node.js projects, Bun works without any changes:

```bash
# Replace node with bun
bun src/app.js

# Replace npm scripts
bun run start
bun run dev

# Replace npx
bunx create-react-app my-app
```

Bun implements the Node.js API (`fs`, `path`, `http`, `crypto`, `stream`, etc.) and resolves `node:*` imports. CommonJS (`require()`) and ESM (`import`) both work, and can be mixed in the same project.

> [!IMPORTANT]
> Some native Node.js addons (`.node` files) may not be compatible with Bun. Check the Bun compatibility tracker at `bun.sh/nodejs` for the current status of any modules you depend on.

### Execute Shell Commands with Bun.$

```typescript
import { $ } from "bun";

// Build pipeline
await $`bun install`;
await $`bun build src/index.ts --outdir dist --minify`;
await $`tar -czf dist.tar.gz dist/`;

// Read output
const branch = await $`git rev-parse --abbrev-ref HEAD`.text();
console.log(`Current branch: ${branch.trim()}`);

// Check exit code without throwing
const result = await $`test -f .env`.quiet().nothrow();
if (result.exitCode !== 0) {
  console.warn("No .env file found, using defaults");
}

// Pipe data in
const json = JSON.stringify({ key: "value" });
await $`cat`.stdin(json).text();
```

### Use Workspaces in a Monorepo

```json
// package.json (root)
{
  "name": "my-monorepo",
  "workspaces": ["packages/*", "apps/*"]
}
```

```bash
# Install all workspace deps at once
bun install

# Run a script in all workspaces
bun run --filter "*" build

# Run in specific workspaces
bun run --filter "packages/ui" test
bun run --filter "apps/*" dev --parallel
```

Each workspace gets its own `node_modules/.bin` entries, but Bun deduplicates packages at the top level.

### Connect to PostgreSQL with the Built-In SQL Client

```typescript
import { sql } from "bun";

// Set DATABASE_URL in your .env
// DATABASE_URL=postgresql://user:pass@localhost:5432/mydb

// Query
const users = await sql`
  SELECT id, name, email
  FROM users
  WHERE created_at > ${new Date(Date.now() - 86400_000)}
  ORDER BY created_at DESC
  LIMIT 10
`;

// Parameterized inserts
const [newUser] = await sql`
  INSERT INTO users (name, email)
  VALUES (${name}, ${email})
  RETURNING *
`;

console.log(newUser.id);
```

For MySQL:

```typescript
const db = new Bun.sql("mysql://user:pass@localhost:3306/mydb");
const rows = await db`SELECT * FROM products LIMIT 5`;
```

### Render Markdown to HTML

```typescript
const markdown = `
# Getting Started

Install Bun with:

\`\`\`bash
curl -fsSL https://bun.sh/install | bash
\`\`\`

Then run any TypeScript file **directly**.
`;

const html = Bun.markdown.html(markdown);
// Returns fully-rendered HTML string

// In a Bun.serve() handler:
Bun.serve({
  port: 3000,
  fetch() {
    return new Response(html, {
      headers: { "Content-Type": "text/html; charset=utf-8" },
    });
  },
});
```

---

## 6. Troubleshooting

### Error: `Cannot find module './utils'`

**Cause:** Bun resolves modules according to Node.js resolution rules. Missing file extension or incorrect path casing on case-sensitive filesystems.

**Solution:**
1. Ensure the import path matches the filename exactly (case-sensitive on Linux).
2. Add the file extension if using `.ts` files that import other `.ts` files: `import { foo } from './utils.ts'` — Bun supports explicit `.ts` extensions in imports.
3. Check that `tsconfig.json` `paths` aliases are defined correctly if using aliased imports.

**Prevention:** Use an editor with TypeScript support (VS Code + the Bun extension) to catch missing module errors at edit time.

---

### Error: `EPERM: operation not permitted` during `bun install`

**Cause:** Tracked in issue #29398. Occurs when patching packages on Windows or when the `--backend` uses filesystem operations that require elevated permissions.

**Solution:**
1. On Windows, try switching the install backend: `bun install --backend copyfile`
2. Ensure no antivirus or security software is holding file locks on `node_modules`.
3. Delete `node_modules` and `bun.lockb`, then retry: `rm -rf node_modules bun.lockb && bun install`

---

### Error: `EADDRINUSE: Address already in use` in VS Code

**Cause:** Tracked in issue #16242. The integrated VS Code terminal can hold open a previous Bun process's port, especially when stopping a dev server with Ctrl+C.

**Solution:**
1. Kill the process holding the port: `lsof -ti:3000 | xargs kill -9` (macOS/Linux) or use Task Manager on Windows.
2. Use a different port: `bun run --port 3001 server.ts`
3. Switch to an external terminal for running Bun dev servers.

---

### Error: `Segmentation fault` when using FFI on Linux x64

**Cause:** Tracked in issue #29346. Certain FFI (Foreign Function Interface) call patterns cause a segfault on Linux x64 in Bun 1.x.

**Solution:**
1. Check if your FFI signature matches the native library's actual ABI exactly (including calling convention).
2. Ensure all pointer types are declared correctly in `FFIType`.
3. If the segfault is reproducible and your FFI code looks correct, file a bug on the Bun GitHub tracker referencing issue #29346.

---

### Error: `Segmentation fault` in HTTP server

**Cause:** Tracked in issue #15281. Certain request patterns or server configurations can cause a server crash in specific Bun versions.

**Solution:**
1. Upgrade Bun: `bun upgrade`
2. Wrap your fetch handler in a try/catch to prevent unhandled errors from crashing the process.
3. Enable the `--watch` flag during development so the process auto-restarts.

---

### Error: Codesign failure with `bun build --compile` on macOS

**Cause:** Tracked in issue #29361. A regression introduced codesigning issues for compiled binaries on macOS.

**Solution:**
1. Upgrade Bun: `bun upgrade`
2. Manually re-sign the binary: `codesign --force --deep --sign - ./my-binary`
3. If distributing, use a proper Apple Developer ID signature.

---

### Error: `bun install` not linking bin from a package (e.g., `@anthropic-ai/claude-code`)

**Cause:** Tracked in issue #29399. Certain packages with `bin` fields in their `package.json` are not correctly linked into `.bin/` after install.

**Solution:**
1. Run `bun pm bin` to confirm the bin directory location.
2. Delete `node_modules` and reinstall: `rm -rf node_modules && bun install`
3. Add `--trust` flag for packages with lifecycle scripts: `bun add --trust @anthropic-ai/claude-code`
4. As a workaround, run the package directly: `bunx @anthropic-ai/claude-code`

---

### Error: Drive root path failure on Windows

**Cause:** Tracked in issue #29273. Paths beginning at a Windows drive root (e.g., `C:\`) may not resolve correctly in certain Bun APIs.

**Solution:**
1. Use forward slashes: `C:/Users/...` instead of `C:\Users\...`
2. Use relative paths where possible.
3. Upgrade Bun: `bun upgrade`

---

### Error: `File.type` returns wrong charset

**Cause:** Tracked in issue #29257. `BunFile.type` (MIME type) may include an incorrect or missing `charset` component for certain file types.

**Solution:**
1. Explicitly set the `Content-Type` header in HTTP responses rather than relying on `Bun.file().type`.
2. Use `new Response(body, { headers: { "Content-Type": "text/html; charset=utf-8" } })`.

---

### Memory Leak with MongoDB

**Cause:** Tracked in issue #12117. A memory leak occurs when using the `mongodb` npm package with Bun under sustained connection load.

**Solution:**
1. Implement connection pooling and explicitly close connections when done.
2. Monitor memory with `process.memoryUsage()` to confirm the leak.
3. Consider using a managed connection pool library (e.g., `mongoose` with `autoIndex: false` to reduce connection churn).
4. Check for a newer version of `mongodb` that may have patched the underlying issue.
5. File a reproduction on the Bun GitHub tracker referencing issue #12117 if the leak persists on current versions.

---

### 100% CPU Usage When Debugging

**Cause:** Tracked in issue #21654. The Bun debugger (`--inspect`) can spin at 100% CPU in certain debug session configurations.

**Solution:**
1. Use `--inspect-wait` instead of `--inspect` to ensure the debugger attaches before execution begins.
2. Set breakpoints before resuming execution.
3. Disconnect and reconnect the debugger if CPU usage spikes.
4. Upgrade Bun: `bun upgrade`

---

### Lockfile Conflicts (bun.lockb vs bun.lock)

**Cause:** Projects switching between binary (`bun.lockb`) and text (`bun.lock`) lockfile formats, or teams using different Bun versions, can encounter conflicts.

**Solution:**
1. Agree on one format. Add `save-text-lockfile = true` to `bunfig.toml` to use the text format for easier code review.
2. Delete the old lockfile and regenerate: `rm bun.lockb && bun install --save-text-lockfile`
3. In CI, always use `--frozen-lockfile` to fail fast on drift.

---

### bunfig.toml Parse Errors

**Cause:** TOML syntax errors or incorrect types in `bunfig.toml`.

**Solution:**
1. Validate your TOML at `tomllib.dev` or with `python3 -c "import tomllib; tomllib.loads(open('bunfig.toml').read())"`.
2. Common mistake: using `"true"` (string) instead of `true` (boolean).
3. Check for stray commas — TOML (unlike JSON) does not allow trailing commas.

**Example of a correct section:**

```toml
[install]
production = false        # boolean, not "false"
frozen-lockfile = false   # boolean
```

---

### Error: TypeScript path aliases not resolving at runtime

**Cause:** `tsconfig.json` path aliases are not configured in `bunfig.toml` or in a way Bun recognizes.

**Solution:** Bun reads `compilerOptions.paths` from `tsconfig.json` automatically. Ensure your `tsconfig.json` is at the project root and the `baseUrl` is set:

```json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@utils/*": ["src/utils/*"],
      "@types/*": ["src/types/*"]
    }
  }
}
```

No additional Bun configuration is needed.

---

### Error: `bun: command not found` after install

**Cause:** The Bun binary directory (`~/.bun/bin`) is not in your PATH.

**Solution:**

```bash
# Add to ~/.bashrc or ~/.zshrc:
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"

# Then reload:
source ~/.bashrc
```

---

## 7. FAQ

**How do I switch from npm to Bun?**
Drop-in replacement: run `bun install` instead of `npm install`, `bun run <script>` instead of `npm run <script>`, and `bun add <pkg>` instead of `npm install <pkg>`. Your `package.json` and existing `node_modules` structure remain unchanged. Bun reads `package.json` the same way npm does.

**How do I switch from yarn or pnpm to Bun?**
The same principle applies. Bun understands `yarn.lock` and `pnpm-lock.yaml` and can migrate from them: running `bun install` will replace either lockfile with `bun.lockb`. Delete the old lockfile after migrating to avoid confusion.

**Is Bun compatible with Node.js?**
Bun implements the Node.js API surface including `fs`, `path`, `http`, `https`, `crypto`, `stream`, `buffer`, `child_process`, `worker_threads`, `os`, `net`, and more. Most Node.js code runs without modification. Gaps and known incompatibilities are tracked at `bun.sh/nodejs`. Native addons (`.node` files compiled for Node.js) may not work.

**Does Bun work on Windows?**
Yes. Bun has full Windows support for x64 and arm64. The built-in shell (`Bun.$`) handles cross-platform scripting so you don't need WSL for most tasks. Install via `scoop install bun` or the npm package (`npm install -g bun`).

**How do I use Bun with Docker?**
Use the official `oven/bun` images. A minimal production Dockerfile:

```dockerfile
FROM oven/bun:1.3.13-alpine AS builder
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile --production
COPY src/ ./src/

FROM oven/bun:1.3.13-distroless
WORKDIR /app
COPY --from=builder /app .
CMD ["bun", "run", "src/server.ts"]
```

**What file types does Bun support natively?**
`.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`, `.mts`, `.cts` — all executed natively without plugins. Bun also handles `.json` (imported as objects), `.toml` (imported as objects), `.txt` (imported as strings), and `.html` (in the experimental Bun Bake bundler).

**How do I debug with VS Code?**
Start Bun with the inspector enabled:

```bash
bun run --inspect-wait src/server.ts
```

In VS Code, open the Run and Debug panel, create a `launch.json` with type `"bun"`, and attach to `ws://localhost:6499`. The Bun VS Code extension (available in the marketplace) automates this configuration.

> [!WARNING]
> Running Bun with `--inspect` may cause 100% CPU usage in some versions (issue #21654). Use `--inspect-wait` and set breakpoints before resuming to mitigate this.

**How do I generate a standalone executable?**
Use `bun build --compile`:

```bash
bun build src/cli.ts --compile --outfile my-tool
```

The resulting binary includes the Bun runtime and your code. It runs on any machine with the same OS and architecture — no Bun, Node.js, or npm required.

**What's the difference between `--watch` and `--hot`?**
`--watch` restarts the process cleanly on file changes (new process, fresh state). `--hot` hot-patches changed modules into the running process (same process, preserved state). Use `--watch` for CLIs and scripts; use `--hot` for HTTP servers where you don't want to drop connections.

**How do I use workspaces in a monorepo?**
Add a `workspaces` field to your root `package.json`:

```json
{ "workspaces": ["packages/*", "apps/*"] }
```

Then `bun install` at the root installs all workspace dependencies. Use `bun run --filter "packages/*" build` to run scripts across workspaces.

**Can Bun replace webpack or esbuild?**
For most use cases, yes. `bun build` handles tree-shaking, code splitting, source maps, minification, and targets (browser, Node.js, Bun). It reads `tsconfig.json` path aliases. For highly customized webpack configs with obscure loaders, you may need to migrate plugin logic, but Bun's build API supports custom plugins written in TypeScript.

**Does Bun support ESM and CommonJS?**
Both. You can `import` and `require()` in the same file. Bun resolves `.mjs` as ESM, `.cjs` as CommonJS, and `.js` based on the `"type"` field in `package.json`. ESM packages that conditionally export based on `"exports"` are fully supported.

**How do I use Bun with an existing Node.js project?**
1. Install Bun: `curl -fsSL https://bun.sh/install | bash`
2. In your project directory: `bun install` (replaces `npm install`)
3. Replace `node src/server.js` with `bun src/server.js` in your scripts
4. Test thoroughly — most projects work without changes

**How do I configure test coverage thresholds?**
Bun does not yet enforce minimum coverage thresholds via CLI flags (use a separate tool like `nyc` for enforcement). However, you can fail the CI pipeline by checking the text output:

```bash
bun test --coverage 2>&1 | tee coverage.txt
# Parse coverage.txt for your threshold check
```

Configure reporters and output directory in `bunfig.toml`:

```toml
[test]
coverage = true
coverageReporter = ["text", "lcov"]
coverageDir = "coverage"
```

**What is `bunfig.toml`?**
`bunfig.toml` is Bun's configuration file, analogous to `.npmrc` or `jest.config.ts`. It configures the package manager (`[install]`), script runner (`[run]`), test runner (`[test]`), and more. Place it at the project root or at `~/.bunfig.toml` for global defaults. Bun merges both files, with the project-level file taking precedence.

**What's the difference between `bun run` and `bun exec`?**
`bun run <file>` runs a JavaScript/TypeScript file using Bun's runtime, or a script name from `package.json`. `bun exec <script.sh>` executes a shell script file using Bun's built-in cross-platform shell — equivalent to running `bash script.sh` but without requiring bash on the system, making it useful for cross-platform scripts on Windows.

**How do I use the built-in Redis client?**
Set `REDIS_URL` in your environment and use `Bun.redis`:

```typescript
const client = new Bun.RedisClient("redis://localhost:6379");
await client.set("key", "value");
const val = await client.get("key");
// "value"
await client.disconnect();

// Or use the default client (reads REDIS_URL)
await Bun.redis.set("count", 1);
```

**How do I use the built-in S3 client?**
```typescript
const s3 = new Bun.S3Client({
  region: "us-east-1",
  accessKeyId: Bun.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: Bun.env.AWS_SECRET_ACCESS_KEY,
  bucket: "my-bucket",
});

// Upload
await s3.write("uploads/image.png", imageBuffer);

// Download
const file = s3.file("uploads/image.png");
const data = await file.arrayBuffer();

// Or use the default client (reads AWS_* env vars)
const file = Bun.s3("s3://my-bucket/key.txt");
```

**How do I transpile code programmatically?**

```typescript
const transpiler = new Bun.Transpiler({
  loader: "ts",
  target: "browser",
});

const result = await transpiler.transform(`
  const greet = (name: string) => \`Hello, \${name}!\`;
  export { greet };
`);

console.log(result);
// const greet = (name) => `Hello, ${name}!`;
// export { greet };
```

---

_Generated May 2026 from oven-sh/bun at 9ed6e89. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
