JavaScript 7 min read

Bun: The Fast JavaScript Runtime and Toolkit

Master Bun for JavaScript development. Learn the runtime, package manager, bundler, test runner, and build faster applications with Bun.

MR

Moshiour Rahman

· Updated May 9, 2026

What is Bun?

Bun is a fast all-in-one JavaScript runtime, bundler, transpiler, and package manager. Built from scratch in Zig, it’s designed to be a drop-in replacement for Node.js with dramatically better performance.

Bun vs Node.js

FeatureBunNode.js
Speed4x fasterBaseline
TypeScriptNativeRequires setup
JSXNativeRequires setup
Package ManagerBuilt-innpm/yarn
BundlerBuilt-inExternal
Test RunnerBuilt-inExternal

Getting Started

Installation

# macOS/Linux
curl -fsSL https://bun.sh/install | bash

# Windows (via WSL)
curl -fsSL https://bun.sh/install | bash

# Homebrew
brew install oven-sh/bun/bun

# npm
npm install -g bun

Create Project

# Create new project
bun init

# Create from template
bun create react my-app
bun create next my-app
bun create svelte my-app

Running JavaScript/TypeScript

Execute Files

# Run JavaScript
bun run index.js

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

# Run with watch mode
bun --watch run index.ts

# Run script from package.json
bun run dev
bun dev  # shorthand

TypeScript Support

// index.ts - No configuration needed!
interface User {
  id: number;
  name: string;
  email: string;
}

const users: User[] = [
  { id: 1, name: 'John', email: 'john@example.com' }
];

console.log(users);

// JSX works too
const element = <div>Hello World</div>;

Package Manager

Install Dependencies

# Install all dependencies
bun install

# Add package
bun add express
bun add -d typescript  # dev dependency

# Add specific version
bun add react@18.2.0

# Remove package
bun remove express

# Update packages
bun update
bun update react

# Global install
bun add -g typescript

Workspace Support

// package.json
{
  "workspaces": [
    "packages/*"
  ]
}
# Install workspace dependencies
bun install

# Run command in workspace
bun --filter my-package run build

HTTP Server

Basic Server

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

    if (url.pathname === '/') {
      return new Response('Hello World!');
    }

    if (url.pathname === '/json') {
      return Response.json({ message: 'Hello JSON' });
    }

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

console.log(`Server running at http://localhost:${server.port}`);

Routing

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

    // GET /api/users
    if (method === 'GET' && url.pathname === '/api/users') {
      const users = await getUsers();
      return Response.json(users);
    }

    // POST /api/users
    if (method === 'POST' && url.pathname === '/api/users') {
      const body = await req.json();
      const user = await createUser(body);
      return Response.json(user, { status: 201 });
    }

    // GET /api/users/:id
    const userMatch = url.pathname.match(/^\/api\/users\/(\d+)$/);
    if (method === 'GET' && userMatch) {
      const user = await getUser(userMatch[1]);
      if (!user) {
        return Response.json({ error: 'Not found' }, { status: 404 });
      }
      return Response.json(user);
    }

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

WebSocket Server

const server = Bun.serve({
  port: 3000,
  fetch(req, server) {
    // Upgrade to WebSocket
    if (server.upgrade(req)) {
      return;
    }
    return new Response('Expected WebSocket', { status: 400 });
  },
  websocket: {
    open(ws) {
      console.log('Client connected');
      ws.subscribe('chat');
    },
    message(ws, message) {
      console.log('Received:', message);
      // Broadcast to all subscribers
      ws.publish('chat', message);
    },
    close(ws) {
      console.log('Client disconnected');
      ws.unsubscribe('chat');
    }
  }
});

File I/O

Reading Files

// Read as text
const text = await Bun.file('file.txt').text();

// Read as JSON
const config = await Bun.file('config.json').json();

// Read as ArrayBuffer
const buffer = await Bun.file('image.png').arrayBuffer();

// Read as stream
const file = Bun.file('large-file.txt');
const stream = file.stream();

// Check if file exists
const exists = await Bun.file('file.txt').exists();

// Get file info
const file = Bun.file('file.txt');
console.log(file.size);  // bytes
console.log(file.type);  // MIME type

Writing Files

// Write text
await Bun.write('output.txt', 'Hello World');

// Write JSON
await Bun.write('data.json', JSON.stringify({ name: 'John' }));

// Write from Response
const response = await fetch('https://example.com/file');
await Bun.write('downloaded.html', response);

// Append to file
const file = Bun.file('log.txt');
const writer = file.writer();
writer.write('Log entry 1\n');
writer.write('Log entry 2\n');
await writer.end();

SQLite Database

import { Database } from 'bun:sqlite';

// Create/open database
const db = new Database('mydb.sqlite');

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

// Insert data
const insert = db.prepare(
  'INSERT INTO users (name, email) VALUES (?, ?)'
);
insert.run('John', 'john@example.com');

// Query data
const query = db.prepare('SELECT * FROM users WHERE id = ?');
const user = query.get(1);
console.log(user);

// Query all
const allUsers = db.prepare('SELECT * FROM users').all();
console.log(allUsers);

// Transaction
const insertMany = db.transaction((users) => {
  const insert = db.prepare(
    'INSERT INTO users (name, email) VALUES (?, ?)'
  );
  for (const user of users) {
    insert.run(user.name, user.email);
  }
});

insertMany([
  { name: 'Alice', email: 'alice@example.com' },
  { name: 'Bob', email: 'bob@example.com' }
]);

Bundler

Bundle for Browser

# Bundle JavaScript
bun build ./src/index.ts --outdir ./dist

# With minification
bun build ./src/index.ts --outdir ./dist --minify

# Multiple entry points
bun build ./src/index.ts ./src/worker.ts --outdir ./dist

# External dependencies
bun build ./src/index.ts --outdir ./dist --external react

Build Configuration

// build.ts
await Bun.build({
  entrypoints: ['./src/index.tsx'],
  outdir: './dist',
  minify: true,
  splitting: true,
  sourcemap: 'external',
  target: 'browser',
  define: {
    'process.env.NODE_ENV': JSON.stringify('production')
  },
  external: ['react', 'react-dom']
});

Test Runner

Writing Tests

// math.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'bun:test';

describe('Math operations', () => {
  it('should add numbers', () => {
    expect(1 + 1).toBe(2);
  });

  it('should multiply numbers', () => {
    expect(2 * 3).toBe(6);
  });
});

describe('Async tests', () => {
  it('should handle async operations', async () => {
    const result = await Promise.resolve(42);
    expect(result).toBe(42);
  });
});

describe('Matchers', () => {
  it('toBe', () => {
    expect(1).toBe(1);
  });

  it('toEqual', () => {
    expect({ a: 1 }).toEqual({ a: 1 });
  });

  it('toContain', () => {
    expect([1, 2, 3]).toContain(2);
  });

  it('toThrow', () => {
    expect(() => {
      throw new Error('fail');
    }).toThrow('fail');
  });

  it('toBeGreaterThan', () => {
    expect(10).toBeGreaterThan(5);
  });
});

Run Tests

# Run all tests
bun test

# Run specific file
bun test math.test.ts

# Watch mode
bun test --watch

# With coverage
bun test --coverage

Mocking

import { mock, spyOn } from 'bun:test';

// Mock function
const mockFn = mock(() => 42);
mockFn();
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(1);

// Spy on object method
const obj = {
  method: () => 'original'
};

const spy = spyOn(obj, 'method').mockReturnValue('mocked');
expect(obj.method()).toBe('mocked');
expect(spy).toHaveBeenCalled();

Environment Variables

// Access environment variables
const apiKey = Bun.env.API_KEY;
const port = Bun.env.PORT || 3000;

// .env files are loaded automatically
// .env
// API_KEY=secret123
// PORT=8080

// Access with process.env (Node.js compatibility)
console.log(process.env.API_KEY);

Shell Commands

import { $ } from 'bun';

// Run shell commands
const result = await $`ls -la`;
console.log(result.text());

// With variables
const dir = './src';
await $`ls ${dir}`;

// Check exit code
const { exitCode } = await $`npm test`;
if (exitCode !== 0) {
  console.log('Tests failed');
}

// Pipe commands
await $`cat file.txt | grep "pattern"`;

// Capture output
const output = await $`echo "Hello"`.text();
console.log(output);  // "Hello\n"

Node.js Compatibility

// Most Node.js APIs work
import fs from 'fs';
import path from 'path';
import { createServer } from 'http';

// Read file (Node.js style)
const content = fs.readFileSync('file.txt', 'utf-8');

// Create HTTP server (Node.js style)
const server = createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello World\n');
});

server.listen(3000);

Hono Framework

// Perfect combination with Hono
import { Hono } from 'hono';

const app = new Hono();

app.get('/', (c) => c.text('Hello Hono!'));

app.get('/api/users', async (c) => {
  const users = await getUsers();
  return c.json(users);
});

app.post('/api/users', async (c) => {
  const body = await c.req.json();
  const user = await createUser(body);
  return c.json(user, 201);
});

export default app;

// Or with Bun.serve
export default {
  port: 3000,
  fetch: app.fetch
};

Summary

FeatureCommand
Runbun run file.ts
Installbun install
Add Packagebun add package
Buildbun build
Testbun test
Start Serverbun run server.ts

Bun provides a fast, all-in-one toolkit for modern JavaScript and TypeScript development.

Is your AI API down right now? Check live status for OpenAI, Claude, Gemini, Groq, and more.
Check status →
MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.