Skip to main content
โšก Calmops

Bun Runtime: The Fast JavaScript All-in-One Runtime

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

External Resources

Comments