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

Advertisement

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.

Advertisement

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.