DevToolBoxGRATIS
Blog

Bun: The Complete Guide to the All-in-One JavaScript Runtime

20 min readby DevToolBox Team

Bun is an all-in-one JavaScript runtime, package manager, bundler, and test runner built from the ground up for speed. Written in Zig and powered by the JavaScriptCore engine (the same engine used by Safari), Bun delivers dramatically faster startup times, package installs, and HTTP throughput compared to Node.js. This guide covers every major feature of Bun in 2026, from the basics to advanced capabilities like SQLite integration, shell scripting, and macros.

TL;DR

Bun is a fast, all-in-one JavaScript and TypeScript runtime written in Zig. It replaces Node.js, npm, webpack, and Jest with a single tool. It uses JavaScriptCore instead of V8, installs packages 25x faster than npm, has a built-in bundler, test runner, SQLite client, and HTTP server. It is production-ready in 2026 with near-complete Node.js compatibility.

Key Takeaways
  • Bun uses JavaScriptCore (WebKit engine) and Zig for maximum performance, achieving 4x faster startup than Node.js.
  • bun install is up to 25x faster than npm thanks to binary lockfiles, global cache, and native code.
  • Bun.serve() provides a high-performance HTTP server handling 100K+ requests per second out of the box.
  • Built-in SQLite, test runner, bundler, and .env loading eliminate the need for external dependencies.
  • Near-complete Node.js API compatibility means most npm packages work without modification.

Why Bun Is Fast: Zig and JavaScriptCore

Bun achieves its speed through two key architectural decisions. First, it is written in Zig, a low-level systems language designed for performance-critical software. Zig has no hidden control flow, no garbage collector, and compiles to highly optimized machine code. Second, Bun uses JavaScriptCore (JSC) from WebKit rather than V8 (used by Node.js and Deno). JSC has a faster startup time because it uses a lightweight interpreter tier before JIT compilation kicks in, whereas V8 eagerly compiles code. This means Bun scripts start executing almost instantly.

AspectBun (JavaScriptCore)Node.js / Deno (V8)
Startup StrategyInterpreter first, then JITEager compilation
Implementation LanguageZig (no GC, no hidden control flow)C++ (Node) / Rust (Deno)
Startup Time~5ms for hello world~20ms for hello world
I/O LayerCustom event loop (io_uring on Linux)libuv

Installation and Getting Started

Bun installs as a single binary with no external dependencies. It works on macOS, Linux, and Windows (via WSL or native).

# Install Bun (macOS / Linux)
curl -fsSL https://bun.sh/install | bash

# Install via npm (alternative)
npm install -g bun

# Install via Homebrew (macOS)
brew install oven-sh/bun/bun

# Windows (native support)
powershell -c "irm bun.sh/install.ps1 | iex"

# Verify installation
bun --version  # 1.x.x

# Create a new project
bun init
# Creates: package.json, tsconfig.json, index.ts, README.md

# Run a TypeScript file directly (no config needed)
bun run index.ts

# Run with watch mode (auto-restart on changes)
bun --watch run index.ts

Package Manager: bun install

Bun includes the fastest JavaScript package manager available. It reads package.json, resolves dependencies from the npm registry, and writes to node_modules. The speed advantage comes from a binary lockfile (bun.lockb), parallel HTTP requests using native code, a global package cache, and symlink-based node_modules similar to pnpm.

# Install all dependencies from package.json
bun install

# Add a dependency
bun add express
bun add zod @types/node

# Add dev dependency
bun add -d typescript prettier eslint

# Add global package
bun add -g serve

# Remove a package
bun remove lodash

# Update all packages
bun update

# Run a script from package.json
bun run build
bun run dev

# CI mode: fail if lockfile is out of date
bun install --frozen-lockfile

# View lockfile as human-readable text
bun bun.lockb

# Execute a package binary (like npx)
bunx create-next-app@latest my-app
bunx prettier --write .

Install Speed Benchmarks

Package ManagerWarm CacheCold CacheLockfile Format
bun install1.2s4.1sBinary (bun.lockb)
pnpm install9.4s15.2sYAML
yarn install14.1s22.8sCustom text
npm install28.3s38.7sJSON

Bundler: bun build

Bun includes a production-ready JavaScript and TypeScript bundler. It supports tree shaking, code splitting, minification, source maps, and multiple output targets (browser, node, bun). It aims to be a faster alternative to esbuild and webpack for most use cases.

# Bundle for the browser
bun build ./src/index.ts --outdir ./dist --target browser

# Bundle for Node.js
bun build ./src/server.ts --outdir ./dist --target node

# Bundle for Bun runtime
bun build ./src/app.ts --outdir ./dist --target bun

# With minification and code splitting
bun build ./src/index.ts \
  --outdir ./dist \
  --target browser \
  --minify \
  --splitting \
  --sourcemap=external

# Programmatic API (build.ts)
const result = await Bun.build({
  entrypoints: ["./src/index.ts", "./src/worker.ts"],
  outdir: "./dist",
  target: "browser",
  minify: true,
  splitting: true,
  sourcemap: "external",
  naming: "[dir]/[name]-[hash].[ext]",
  define: {
    "process.env.NODE_ENV": JSON.stringify("production"),
  },
});

if (!result.success) {
  for (const msg of result.logs) {
    console.error(msg);
  }
}

Test Runner: bun test

Bun has a built-in test runner with a Jest-compatible API. It supports describe, test, expect, beforeAll, afterAll, beforeEach, afterEach, mocking, snapshots, and code coverage. Tests run significantly faster than Jest because there is no separate transpilation step and the runtime itself is faster.

// math.test.ts
import { describe, test, expect, beforeAll, mock } from "bun:test";

describe("math utilities", () => {
  test("adds two numbers", () => {
    expect(2 + 3).toBe(5);
  });

  test("array contains value", () => {
    const fruits = ["apple", "banana", "cherry"];
    expect(fruits).toContain("banana");
    expect(fruits).toHaveLength(3);
  });

  test("object matching", () => {
    const user = { name: "Alice", age: 30, role: "admin" };
    expect(user).toMatchObject({ name: "Alice", role: "admin" });
  });

  test("async operations", async () => {
    const data = await Promise.resolve({ status: "ok" });
    expect(data.status).toBe("ok");
  });

  test("error throwing", () => {
    expect(() => { throw new Error("fail"); }).toThrow("fail");
  });
});

// Mocking example
const mockFetch = mock(() => Promise.resolve({ ok: true }));
test("mock function", () => {
  mockFetch();
  expect(mockFetch).toHaveBeenCalledTimes(1);
});

Test Runner CLI Options

# Run all tests
bun test

# Run specific test file
bun test src/utils.test.ts

# Watch mode
bun test --watch

# With code coverage
bun test --coverage

# Filter tests by name
bun test --test-name-pattern "math"

# Set timeout (default 5000ms)
bun test --timeout 10000

HTTP Server: Bun.serve()

Bun.serve() is a high-performance HTTP server built into the runtime. It uses the Web standard Request and Response APIs, supports WebSocket upgrades, TLS, streaming, and can handle over 100,000 requests per second on modest hardware.

// server.ts β€” High-performance HTTP server
const server = Bun.serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);

    if (url.pathname === "/") {
      return new Response("Hello from Bun!");
    }

    if (url.pathname === "/api/users") {
      const users = [
        { id: 1, name: "Alice" },
        { id: 2, name: "Bob" },
      ];
      return Response.json(users);
    }

    if (url.pathname === "/api/stream") {
      const stream = new ReadableStream({
        start(controller) {
          controller.enqueue("chunk 1\n");
          controller.enqueue("chunk 2\n");
          controller.close();
        },
      });
      return new Response(stream);
    }

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

console.log("Server running at http://localhost:" + server.port);

WebSocket Server

// WebSocket server with Bun.serve()
Bun.serve({
  port: 3000,
  fetch(req, server) {
    // Upgrade HTTP request to WebSocket
    if (server.upgrade(req)) {
      return; // Return nothing if upgraded
    }
    return new Response("Upgrade failed", { status: 500 });
  },
  websocket: {
    open(ws) {
      console.log("Client connected");
      ws.send("Welcome!");
    },
    message(ws, message) {
      console.log("Received:", message);
      ws.send("Echo: " + message);
    },
    close(ws) {
      console.log("Client disconnected");
    },
  },
});

File I/O: Bun.file() and Bun.write()

Bun provides optimized file I/O APIs that are significantly faster than Node.js equivalents. Bun.file() creates a lazy reference to a file, and Bun.write() writes data to disk. Both support text, JSON, ArrayBuffer, Blob, and streams.

// Reading files
const file = Bun.file("./data.json");
console.log(file.size);       // File size in bytes
console.log(file.type);       // MIME type

const text = await file.text();       // Read as string
const json = await file.json();       // Parse as JSON
const buffer = await file.arrayBuffer(); // Read as ArrayBuffer
const bytes = await file.bytes();     // Read as Uint8Array

// Writing files
await Bun.write("output.txt", "Hello, Bun!");
await Bun.write("data.json", JSON.stringify({ key: "value" }));
await Bun.write("copy.txt", Bun.file("original.txt"));

// Write Response body to file
const response = await fetch("https://example.com/data.json");
await Bun.write("downloaded.json", response);

// Streaming large files
const writer = Bun.file("large-output.txt").writer();
writer.write("line 1\n");
writer.write("line 2\n");
writer.flush();
writer.end();

Built-in SQLite: bun:sqlite

Bun includes a native SQLite client via the bun:sqlite module. There is no need to install any npm package. It is one of the fastest SQLite bindings available for any JavaScript runtime, supporting prepared statements, transactions, WAL mode, and typed results.

// Built-in SQLite β€” no npm install needed
import { Database } from "bun:sqlite";

// Open or create a database
const db = new Database("myapp.db");

// Enable WAL mode for better concurrent performance
db.exec("PRAGMA journal_mode = WAL");

// Create a table
db.exec(`
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP
  )
`);

// Prepared statements (safe from SQL injection)
const insertUser = db.prepare(
  "INSERT INTO users (name, email) VALUES (?, ?)"
);
insertUser.run("Alice", "alice@example.com");
insertUser.run("Bob", "bob@example.com");

// Query with typed results
const allUsers = db.prepare("SELECT * FROM users").all();
console.log(allUsers);
// [{ id: 1, name: "Alice", ... }, { id: 2, name: "Bob", ... }]

// Transactions for batch operations
const insertMany = db.transaction((users) => {
  for (const user of users) {
    insertUser.run(user.name, user.email);
  }
});

insertMany([
  { name: "Charlie", email: "charlie@example.com" },
  { name: "Diana", email: "diana@example.com" },
]);

Shell Scripting: Bun Shell

Bun includes a cross-platform shell (Bun.$) that lets you run shell commands directly from JavaScript or TypeScript. It works on macOS, Linux, and Windows without requiring bash. You can pipe commands, redirect output, and use template literals for interpolation.

// Bun Shell β€” cross-platform shell scripting
import { $ } from "bun";

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

// Pipe commands
const count = await $`cat package.json | wc -l`.text();
console.log("Lines:", count.trim());

// Use variables safely (auto-escaped)
const filename = "my file.txt";
await $`touch ${filename}`;
await $`echo "hello" > ${filename}`;

// Redirect output to a file
await $`echo "build log" > build.log`;

// Check exit code
const proc = await $`grep -r "TODO" src/`.nothrow();
if (proc.exitCode === 0) {
  console.log("Found TODOs:", proc.text());
} else {
  console.log("No TODOs found");
}

// Run in background
const server = $`bun run server.ts`.spawn();
// ... do other work ...
server.kill();

Macros: Compile-Time Code Execution

Bun macros allow you to run JavaScript functions at bundle time and inline the results into the output. This is useful for embedding build metadata, reading configuration files, or generating code at compile time rather than runtime.

// macros.ts β€” runs at compile time, NOT runtime
export function getBuildTime() {
  return new Date().toISOString();
}

export function getGitCommit() {
  const proc = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"]);
  return proc.stdout.toString().trim();
}

// app.ts β€” import with { type: "macro" }
import { getBuildTime, getGitCommit } from "./macros" with { type: "macro" };

// These calls are evaluated at bundle time
// and replaced with their return values
console.log("Built at:", getBuildTime());
console.log("Commit:", getGitCommit());

// After bundling, the output becomes:
// console.log("Built at:", "2026-02-28T10:30:00.000Z");
// console.log("Commit:", "a1b2c3d");

Bun vs Node.js vs Deno: Feature Comparison

Here is a detailed comparison of the three major JavaScript runtimes in 2026.

FeatureBunNode.jsDeno
EngineJavaScriptCoreV8V8
Written InZig + C++C++Rust
TypeScriptNative (transpile)Via --strip-types (22+)Native (type-check)
Package ManagerBuilt-in (bun install)npm / yarn / pnpmBuilt-in (deno add)
BundlerBuilt-in (bun build)External (webpack/vite)Built-in
Test RunnerBuilt-in (Jest API)Built-in (node --test)Built-in (deno test)
HTTP ServerBun.serve()http.createServer()Deno.serve()
SQLiteBuilt-in (bun:sqlite)Via npm (better-sqlite3)Via npm
Security ModelUnrestrictedUnrestrictedPermission-based
npm Compatibility~99%100%~95%+
.env LoadingAutomaticVia dotenvVia --env flag
Startup Speed~4x fasterBaseline~1.5x faster

Best Practices for Using Bun in Production

  • Lockfile management: Commit bun.lockb to version control for reproducible installs. Use --frozen-lockfile in CI pipelines to ensure lockfile consistency.
  • HTTP services: Use Bun.serve() for new HTTP services. It outperforms Express and Fastify on raw throughput while using standard Web APIs.
  • SQLite usage: Leverage the built-in SQLite for local databases, caching layers, and session storage instead of adding external dependencies.
  • Bundling: Use bun build with --minify and --splitting for production frontend bundles. Enable source maps for debugging.
  • Environment variables: Take advantage of automatic .env loading. Bun reads .env, .env.local, and .env.production without the dotenv package.
  • Testing: Write tests using bun test with the built-in Jest-compatible API. No configuration or extra packages needed.

Migrating from Node.js to Bun

Migrating an existing Node.js project to Bun is straightforward because Bun implements the vast majority of Node.js APIs. Here is a step-by-step approach.

// Step 1: Replace npm/yarn/pnpm with bun
# Delete old lockfiles and node_modules
rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml

# Install with Bun
bun install

// Step 2: Update package.json scripts
// Before:
// "dev": "nodemon src/server.ts"
// "test": "jest --coverage"
// "build": "tsc && webpack"

// After:
// "dev": "bun --watch src/server.ts"
// "test": "bun test --coverage"
// "build": "bun build src/index.ts --outdir dist"

// Step 3: Remove unnecessary devDependencies
bun remove ts-node nodemon dotenv jest ts-jest
# Bun handles TypeScript, watching, .env, and testing natively

// Step 4: Update imports (most work as-is)
// Node.js built-in modules work without changes:
import fs from "node:fs";
import path from "node:path";
import crypto from "node:crypto";
// These all work identically in Bun
Migration Tips
  • Start by using Bun only as a package manager (bun install) while keeping Node.js as the runtime. This is the lowest-risk migration path.
  • Gradually switch scripts from node to bun. Test each one in isolation before moving to the next.
  • If a native Node.js addon does not work, check the Bun compatibility tracker or use a pure-JS alternative.
  • Docker images: use oven/bun as the base image for production containers. It is significantly smaller than node images.
  • For CI pipelines, use bun install --frozen-lockfile and bun test to ensure consistency.

When to Choose Bun Over Node.js or Deno

Use CaseBest RuntimeReason
CLI tools and scriptsBunFastest startup time, built-in TypeScript, shell scripting
Serverless functionsBunCold start under 5ms vs 20ms+ for Node.js
High-throughput APIsBunBun.serve() handles 100K+ req/s with Web standard APIs
Enterprise with strict securityDenoPermission-based security model, auditable access
Large legacy Node.js codebaseNode.js100% compatibility, largest ecosystem, most battle-tested
Monorepo with many packagesBun or pnpmBun install speed wins; pnpm has more mature workspace tooling

Frequently Asked Questions

Is Bun production-ready in 2026?

Yes. Bun 1.0 reached stability in September 2023, and subsequent 1.x releases have achieved near-complete Node.js API compatibility. Companies like Vercel, Figma, and Snap use Bun in production. The runtime passes over 99% of the Node.js test suite.

Does Bun work with all npm packages?

Almost all npm packages work with Bun. It implements Node.js built-in modules including fs, path, crypto, http, net, stream, and child_process. Edge cases exist for packages that use native Node.js C++ addons (.node files), though most popular native packages have been ported.

Can I use Bun with Next.js, Remix, or Astro?

Yes for the package manager (bun install) and script runner (bun run dev). For the runtime, Next.js and Astro have experimental Bun support. Remix works well with Bun as the runtime. The package manager is fully compatible with all frameworks today.

How does Bun compare to Deno?

Both are modern JavaScript runtimes aiming to improve on Node.js. Bun focuses on raw speed and Node.js drop-in compatibility, while Deno focuses on security (permission system) and web standards. Bun is faster for startup, installs, and HTTP throughput. Deno has a more mature permission model and better TypeScript type checking.

Why does Bun use JavaScriptCore instead of V8?

JavaScriptCore (JSC) from WebKit has a faster startup time than V8 because it starts with a lightweight interpreter before JIT-compiling hot paths. This architecture is ideal for CLI tools, serverless functions, and short-lived scripts where startup time matters. V8 eagerly compiles code which helps long-running servers but hurts startup.

Does Bun support TypeScript natively?

Yes. Bun transpiles TypeScript files on the fly with no configuration needed. You can run .ts and .tsx files directly with bun run file.ts. The transpiler is built into the runtime and is significantly faster than tsc or ts-node. Note that Bun transpiles but does not type-check; use tsc --noEmit for type checking.

What is the Bun binary lockfile (bun.lockb)?

bun.lockb is a binary-format lockfile that stores resolved package versions, checksums, and registry URLs. It is much faster to parse than JSON-based lockfiles like package-lock.json or yarn.lock. You can view its contents in human-readable form by running bun bun.lockb. Commit it to version control for reproducible installs.

Can I use Bun for frontend bundling in production?

Yes. bun build supports tree shaking, code splitting, minification, CSS bundling, and multiple output formats. It handles JSX, TypeScript, and CSS out of the box. For large-scale production apps, it is competitive with esbuild and Vite, though the ecosystem plugins are more limited.

𝕏 Twitterin LinkedIn
Was dit nuttig?

Blijf op de hoogte

Ontvang wekelijkse dev-tips en nieuwe tools.

Geen spam. Altijd opzegbaar.

Try These Related Tools

{ }JSON Formatterβœ“JSON Validator

Related Articles

Deno: The Complete Guide to the Secure JavaScript Runtime

Master Deno runtime with security permissions, TypeScript support, standard library, HTTP server, testing, npm compatibility, and Deno Deploy.

esbuild: The Complete Guide to the Fastest JavaScript Bundler

Master esbuild for ultra-fast bundling with CLI, JavaScript API, plugins, loaders, minification, source maps, and production optimization.

SWC: The Complete Guide to the Speedy Web Compiler

Master SWC for ultra-fast JavaScript/TypeScript compilation with configuration, transformations, minification, and framework integration.