Claude-skill-registry bun-runtime

Bun runtime patterns and best practices. Package management, bundling, testing, scripts. Use when working with Bun as the JavaScript runtime.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/bun-runtime" ~/.claude/skills/majiayu000-claude-skill-registry-bun-runtime && rm -rf "$T"
manifest: skills/data/bun-runtime/SKILL.md
source content

Bun Runtime - Fast JavaScript Runtime

Purpose

Expert guidance for Bun:

  • Package Management - Fast installation
  • Bundling - Built-in bundler
  • Testing - Vitest-compatible runner
  • Scripts - Task runner
  • APIs - Bun-specific features

Package Management

Install Dependencies

# Install all dependencies
bun install

# Add dependency
bun add zod mongoose

# Add dev dependency
bun add -D typescript @types/node

# Add exact version
bun add react@18.2.0

# Add from GitHub
bun add github:user/repo

# Remove dependency
bun remove lodash

# Update dependencies
bun update

# Update specific package
bun update react

bunfig.toml

# bunfig.toml
[install]
# Disable postinstall scripts for security
ignorescripts = true

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

# Install settings
frozen-lockfile = true

[run]
# Shell for scripts
shell = "bash"

Script Commands

package.json Scripts

{
	"scripts": {
		"dev": "bun run --hot src/index.ts",
		"start": "bun run src/index.ts",
		"build": "bun build src/index.ts --outdir dist",
		"typecheck": "bunx tsc --noEmit",
		"lint": "bunx eslint . --ext .ts,.tsx",
		"lint:fix": "bunx eslint . --ext .ts,.tsx --fix",
		"test": "bun test",
		"test:watch": "bun test --watch",
		"test:coverage": "bun test --coverage"
	}
}

Running Scripts

# Run script
bun run dev
bun run build

# Shorthand (without "run")
bun dev
bun build

# Run TypeScript directly
bun run src/index.ts

# Hot reload
bun run --hot src/index.ts

# Watch mode
bun run --watch src/index.ts

Bundling

Basic Bundle

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

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

# Source maps
bun build ./src/index.ts --outdir ./dist --sourcemap

# Target
bun build ./src/index.ts --outdir ./dist --target=browser
bun build ./src/index.ts --outdir ./dist --target=node
bun build ./src/index.ts --outdir ./dist --target=bun

Build API

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

if (!result.success) {
	console.error('Build failed:');
	for (const log of result.logs) {
		console.error(log);
	}
	process.exit(1);
}

Testing (Vitest-compatible)

Test Configuration

// bunfig.toml
[test];
preload = ['./tests/setup.ts'];
coverage = true;

Test File

// tests/example.test.ts
import { describe, test, expect, beforeEach, afterEach } from 'bun:test';

describe('Feature', () => {
	beforeEach(() => {
		// Setup
	});

	afterEach(() => {
		// Cleanup
	});

	test('should work correctly', () => {
		const result = 1 + 1;
		expect(result).toBe(2);
	});

	test('async operations', async () => {
		const data = await fetchData();
		expect(data).toBeDefined();
	});
});

Mocking

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

// Mock function
const mockFn = mock((x: number) => x * 2);
mockFn(5);
expect(mockFn).toHaveBeenCalledWith(5);
expect(mockFn).toHaveReturnedWith(10);

// Spy on existing function
const spy = spyOn(console, 'log');
console.log('test');
expect(spy).toHaveBeenCalledWith('test');

Bun APIs

File System

// Read file
const text = await Bun.file('path/to/file.txt').text();
const json = await Bun.file('path/to/file.json').json();
const buffer = await Bun.file('path/to/file.bin').arrayBuffer();

// Write file
await Bun.write('output.txt', 'Hello, World!');
await Bun.write('output.json', JSON.stringify({ hello: 'world' }));

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

HTTP Server

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

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

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

// With WebSocket
Bun.serve({
	port: 3000,
	fetch(request, server) {
		if (server.upgrade(request)) {
			return;
		}
		return new Response('Upgrade failed', { status: 500 });
	},
	websocket: {
		open(ws) {
			console.log('Client connected');
		},
		message(ws, message) {
			ws.send(`Echo: ${message}`);
		},
		close(ws) {
			console.log('Client disconnected');
		},
	},
});

Subprocess

// Run command
const result = Bun.spawn(['echo', 'Hello']);
await result.exited;

// Capture output
const proc = Bun.spawn(['git', 'status'], {
	stdout: 'pipe',
});
const output = await new Response(proc.stdout).text();

// With stdin
const proc = Bun.spawn(['cat'], {
	stdin: 'pipe',
	stdout: 'pipe',
});
proc.stdin.write('Hello from stdin!');
proc.stdin.end();

Password Hashing

// Hash password
const hash = await Bun.password.hash('my-password', {
	algorithm: 'bcrypt',
	cost: 10,
});

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

Environment Variables

// Access env vars
const apiKey = Bun.env['API_KEY'];
const nodeEnv = Bun.env['NODE_ENV'] ?? 'development';

// Set env vars
Bun.env['CUSTOM_VAR'] = 'value';

Performance Tips

Use Native APIs

// Prefer Bun APIs over Node.js equivalents

// File reading
// Node.js way (slower)
import { readFile } from 'fs/promises';
const content = await readFile('file.txt', 'utf-8');

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

Import Optimization

// Use namespace imports for tree-shaking
import * as z from 'zod';

// Avoid dynamic imports in hot paths
// Bad:
async function validate(data: unknown) {
	const { z } = await import('zod');
	return z.object({}).parse(data);
}

// Good:
import { z } from 'zod';
function validate(data: unknown) {
	return z.object({}).parse(data);
}

Bundle for Production

# Compile to single executable
bun build --compile ./src/index.ts --outfile myapp

# Run compiled binary
./myapp

Docker Integration

# Use Bun official image
FROM oven/bun:1-alpine AS base

# Install dependencies
FROM base AS deps
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile

# Build
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN bun run build

# Runtime
FROM base AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./

EXPOSE 3000
CMD ["bun", "run", "dist/index.js"]

Agent Integration

This skill is used by:

  • bun-runtime-expert agent
  • quality-checker for running tests
  • build-error-fixer for build issues
  • dockerfile-optimizer for Docker builds

FORBIDDEN

  1. npm
    commands
    - Use
    bun
    instead
  2. Node.js fs when Bun.file works - Use native APIs
  3. Ignoring lockfile - Always use
    --frozen-lockfile
    in CI
  4. Skipping typecheck - Run
    bunx tsc --noEmit

Version

  • v1.0.0 - Initial implementation based on Bun 1.x patterns