home / skills / hoodini / ai-agents-skills / bun

bun skill

/skills/bun

This skill helps you bootstrap and optimize Bun-based projects by guiding installation, tooling, runtime usage, and fast development workflows.

npx playbooks add skill hoodini/ai-agents-skills --skill bun

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
11.1 KB
---
name: bun
description: Build fast applications with Bun JavaScript runtime. Use when creating Bun projects, using Bun APIs, bundling, testing, or optimizing Node.js alternatives. Triggers on Bun, Bun runtime, bun.sh, bunx, Bun serve, Bun test, JavaScript runtime.
---

# Bun - The Fast JavaScript Runtime

Build and run JavaScript/TypeScript applications with Bun's all-in-one toolkit.

## Quick Start

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

# Windows
powershell -c "irm bun.sh/install.ps1 | iex"

# Create new project
bun init

# Run TypeScript directly (no build step!)
bun run index.ts

# Install packages (faster than npm)
bun install

# Run scripts
bun run dev
```

## Package Management

```bash
# Install dependencies
bun install              # Install all from package.json
bun add express          # Add dependency
bun add -d typescript    # Add dev dependency
bun add -g serve         # Add global package

# Remove packages
bun remove express

# Update packages
bun update

# Run package binaries
bunx prisma generate     # Like npx but faster
bunx create-next-app

# Lockfile
bun install --frozen-lockfile  # CI mode
```

### bun.lockb vs package-lock.json
```bash
# Bun uses binary lockfile (bun.lockb) - much faster
# To generate yarn.lock for compatibility:
bun install --yarn

# Import from other lockfiles
bun install  # Auto-detects package-lock.json, yarn.lock
```

## Bun Runtime

### Run Files
```bash
# Run any file
bun run index.ts         # TypeScript
bun run index.js         # JavaScript
bun run index.jsx        # JSX

# Watch mode
bun --watch run index.ts

# Hot reload
bun --hot run server.ts
```

### Built-in APIs
```typescript
// File I/O (super fast)
const file = Bun.file('data.json');
const content = await file.text();
const json = await file.json();
const bytes = await file.arrayBuffer();

// Write files
await Bun.write('output.txt', 'Hello, Bun!');
await Bun.write('data.json', JSON.stringify({ key: 'value' }));
await Bun.write('image.png', await fetch('https://example.com/img.png'));

// File metadata
const file = Bun.file('data.json');
console.log(file.size);       // bytes
console.log(file.type);       // MIME type
console.log(file.lastModified);

// Glob files
const glob = new Bun.Glob('**/*.ts');
for await (const file of glob.scan('.')) {
  console.log(file);
}
```

### HTTP Server
```typescript
// Simple server
const server = Bun.serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);
    
    if (url.pathname === '/') {
      return new Response('Hello, Bun!');
    }
    
    if (url.pathname === '/json') {
      return Response.json({ message: 'Hello!' });
    }
    
    return new Response('Not Found', { status: 404 });
  },
});

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

### Advanced Server
```typescript
Bun.serve({
  port: 3000,
  
  // Main request handler
  async fetch(req, server) {
    const url = new URL(req.url);
    
    // WebSocket upgrade
    if (url.pathname === '/ws') {
      const upgraded = server.upgrade(req, {
        data: { userId: '123' },  // Attach data to socket
      });
      if (upgraded) return undefined;
    }
    
    // Static files
    if (url.pathname.startsWith('/static/')) {
      const filePath = `./public${url.pathname}`;
      const file = Bun.file(filePath);
      if (await file.exists()) {
        return new Response(file);
      }
    }
    
    // JSON API
    if (url.pathname === '/api/data' && req.method === 'POST') {
      const body = await req.json();
      return Response.json({ received: body });
    }
    
    return new Response('Not Found', { status: 404 });
  },
  
  // WebSocket handlers
  websocket: {
    open(ws) {
      console.log('Client connected:', ws.data.userId);
      ws.subscribe('chat');  // Pub/sub
    },
    message(ws, message) {
      // Broadcast to all subscribers
      ws.publish('chat', message);
    },
    close(ws) {
      console.log('Client disconnected');
    },
  },
  
  // Error handling
  error(error) {
    return new Response(`Error: ${error.message}`, { status: 500 });
  },
});
```

### WebSocket Client
```typescript
const ws = new WebSocket('ws://localhost:3000/ws');

ws.onopen = () => {
  ws.send('Hello, server!');
};

ws.onmessage = (event) => {
  console.log('Received:', event.data);
};
```

## Bun APIs

### SQLite (Built-in)
```typescript
import { Database } from 'bun:sqlite';

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
  )
`);

// Insert
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
insert.run('Alice', '[email protected]');

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

// All results
const allUsers = db.prepare('SELECT * FROM users').all();

// Transaction
const insertMany = db.transaction((users) => {
  for (const user of users) {
    insert.run(user.name, user.email);
  }
});

insertMany([
  { name: 'Bob', email: '[email protected]' },
  { name: 'Charlie', email: '[email protected]' },
]);
```

### Password Hashing (Built-in)
```typescript
// Hash password
const hash = await Bun.password.hash('mypassword', {
  algorithm: 'argon2id',  // or 'bcrypt'
  memoryCost: 65536,      // 64 MB
  timeCost: 2,
});

// Verify password
const isValid = await Bun.password.verify('mypassword', hash);
```

### Spawn Processes
```typescript
// Spawn process
const proc = Bun.spawn(['ls', '-la'], {
  cwd: '/home/user',
  env: { ...process.env, MY_VAR: 'value' },
  stdout: 'pipe',
});

const output = await new Response(proc.stdout).text();
console.log(output);

// Spawn sync
const result = Bun.spawnSync(['echo', 'hello']);
console.log(result.stdout.toString());

// Shell command
const { stdout } = Bun.spawn({
  cmd: ['sh', '-c', 'echo $HOME'],
  stdout: 'pipe',
});
```

### Hashing & Crypto
```typescript
// Hash strings
const hash = Bun.hash('hello world');  // Wyhash (fast)

// Crypto hashes
const sha256 = new Bun.CryptoHasher('sha256');
sha256.update('data');
const digest = sha256.digest('hex');

// One-liner
const md5 = Bun.CryptoHasher.hash('md5', 'data', 'hex');

// HMAC
const hmac = Bun.CryptoHasher.hmac('sha256', 'secret-key', 'data', 'hex');
```

## Bundler

```bash
# Bundle for browser
bun build ./src/index.ts --outdir ./dist

# Bundle options
bun build ./src/index.ts \
  --outdir ./dist \
  --minify \
  --sourcemap \
  --target browser \
  --splitting \
  --entry-naming '[dir]/[name]-[hash].[ext]'
```

### Build API
```typescript
const result = await Bun.build({
  entrypoints: ['./src/index.ts'],
  outdir: './dist',
  minify: true,
  sourcemap: 'external',
  target: 'browser',  // 'bun' | 'node' | 'browser'
  splitting: true,
  naming: {
    entry: '[dir]/[name]-[hash].[ext]',
    chunk: '[name]-[hash].[ext]',
    asset: '[name]-[hash].[ext]',
  },
  external: ['react', 'react-dom'],
  define: {
    'process.env.NODE_ENV': JSON.stringify('production'),
  },
  loader: {
    '.png': 'file',
    '.svg': 'text',
  },
});

if (!result.success) {
  console.error('Build failed:', result.logs);
}
```

## Testing

```typescript
// test.ts
import { describe, test, expect, beforeAll, afterAll, mock } from 'bun:test';

describe('Math operations', () => {
  test('addition', () => {
    expect(1 + 1).toBe(2);
  });
  
  test('array contains', () => {
    expect([1, 2, 3]).toContain(2);
  });
  
  test('object matching', () => {
    expect({ name: 'Alice', age: 30 }).toMatchObject({ name: 'Alice' });
  });
  
  test('async test', async () => {
    const result = await Promise.resolve(42);
    expect(result).toBe(42);
  });
  
  test('throws error', () => {
    expect(() => {
      throw new Error('fail');
    }).toThrow('fail');
  });
});

// Mocking
const mockFn = mock(() => 'mocked');
mockFn();
expect(mockFn).toHaveBeenCalled();

// Mock modules
mock.module('./database', () => ({
  query: mock(() => [{ id: 1 }]),
}));
```

```bash
# Run tests
bun test

# Watch mode
bun test --watch

# Specific file
bun test user.test.ts

# Coverage
bun test --coverage
```

## Node.js Compatibility

```typescript
// Most Node.js APIs work out of the box
import fs from 'fs';
import path from 'path';
import { createServer } from 'http';
import express from 'express';

// Bun implements Node.js APIs
const data = fs.readFileSync('file.txt', 'utf-8');
const fullPath = path.join(__dirname, 'file.txt');

// Express works!
const app = express();
app.get('/', (req, res) => res.send('Hello!'));
app.listen(3000);
```

### Node.js vs Bun APIs
```typescript
// Node.js way
import { readFile } from 'fs/promises';
const content = await readFile('file.txt', 'utf-8');

// Bun way (faster)
const content = await Bun.file('file.txt').text();

// Node.js crypto
import crypto from 'crypto';
const hash = crypto.createHash('sha256').update('data').digest('hex');

// Bun way (faster)
const hash = Bun.CryptoHasher.hash('sha256', 'data', 'hex');
```

## Environment Variables

```typescript
// .env file support (built-in, no dotenv needed!)
// .env
// DATABASE_URL=postgres://localhost/db
// API_KEY=secret

// Access env vars
const dbUrl = Bun.env.DATABASE_URL;
const apiKey = process.env.API_KEY;  // Also works

// bunfig.toml for Bun config
// [run]
// preload = ["./setup.ts"]
```

## HTTP Client

```typescript
// Fetch (optimized in Bun)
const response = await fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token',
  },
  body: JSON.stringify({ key: 'value' }),
});

const data = await response.json();

// Streaming response
const response = await fetch('https://api.example.com/stream');
const reader = response.body?.getReader();

while (true) {
  const { done, value } = await reader!.read();
  if (done) break;
  console.log(new TextDecoder().decode(value));
}
```

## Project Structure

```
my-bun-project/
├── src/
│   ├── index.ts          # Entry point
│   ├── routes/
│   │   └── api.ts
│   └── lib/
│       └── database.ts
├── tests/
│   └── index.test.ts
├── public/
│   └── static files
├── package.json
├── bunfig.toml           # Bun config (optional)
├── tsconfig.json
└── .env
```

### bunfig.toml
```toml
[install]
# Use exact versions by default
exact = true

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

[run]
# Scripts to run before `bun run`
preload = ["./instrumentation.ts"]

[test]
# Test configuration
coverage = true
coverageDir = "coverage"

[bundle]
# Default bundle config
minify = true
sourcemap = "external"
```

## Performance Comparison

| Operation | Node.js | Bun | Speedup |
|-----------|---------|-----|---------|
| Start time | ~40ms | ~7ms | 5.7x |
| Package install | ~10s | ~1s | 10x |
| File read | baseline | faster | 10x |
| HTTP server | baseline | faster | 4x |
| SQLite | external | built-in | 3x |
| TypeScript | compile needed | native | ∞ |

## Resources

- **Bun Docs**: https://bun.sh/docs
- **Bun API Reference**: https://bun.sh/docs/api
- **Bun Discord**: https://bun.sh/discord
- **GitHub**: https://github.com/oven-sh/bun

Overview

This skill helps you build, run, and optimize JavaScript and TypeScript projects using the Bun runtime. It provides actionable guidance for Bun CLI commands, Bun-specific APIs (file I/O, HTTP server, SQLite, crypto), bundling, and testing workflows. Use it to speed up development, replace Node tooling, and tune performance-critical paths.

How this skill works

The skill inspects your intent and project context to recommend Bun commands, code snippets, and configuration changes. It suggests CLI steps for installation, package management, bundling, and testing, and offers Bun API examples for servers, file I/O, SQLite, websockets, and process spawning. It also recommends compatibility alternatives for Node APIs and CI-friendly options like frozen lockfiles.

When to use it

  • Starting a new JavaScript/TypeScript project and wanting native TypeScript runtime support
  • Replacing or speeding up Node.js workflows (install, run, test, bundle)
  • Building high-performance HTTP servers or WebSocket services with low latency
  • Bundling for the browser with fast builds and code splitting
  • Adding built-in SQLite, password hashing, or crypto with Bun APIs
  • Optimizing developer CI pipelines (faster installs, frozen lockfiles)

Best practices

  • Use bun init and bun install to bootstrap projects and lock dependencies with bun.lockb for reproducible installs
  • Prefer Bun.file and Bun.write for high-performance file I/O instead of Node fs where possible
  • Run Bun.serve for simple HTTP servers; handle static files, JSON APIs, and WebSocket upgrades inside the fetch handler
  • Use bunx to run package binaries faster (like npx) and bun install --frozen-lockfile in CI
  • Bundle with Bun.build and enable minify, sourcemaps, and splitting only when targeting production
  • Leverage built-in bun:sqlite and Bun.password for local persistence and secure password hashing to reduce external dependencies

Example use cases

  • Create a TypeScript API server: bun init, write handlers using Bun.serve, run with bun run --watch
  • Migrate an Express app: replace slow startup paths with Bun.file for assets and Bun.CryptoHasher for hashing
  • Fast local prototyping: run TypeScript files directly with bun run index.ts, add deps with bun add
  • Bundle a web app: bun build ./src/index.ts --outdir ./dist --minify --splitting
  • Run tests in CI: bun test --coverage and bun install --frozen-lockfile for deterministic installs

FAQ

Does Bun run TypeScript without a separate compile step?

Yes. Bun can execute TypeScript files directly (bun run index.ts) and provides fast runtime TypeScript handling for development.

Is Bun fully compatible with Node.js packages and APIs?

Many Node APIs work out of the box and most packages run, but some native modules or edge cases may require adjustments. Use Bun's compatibility and fall back to Node-specific implementations when needed.