Claude-skill-registry bun-expert
git clone https://github.com/majiayu000/claude-skill-registry
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-expert" ~/.claude/skills/majiayu000-claude-skill-registry-bun-expert && rm -rf "$T"
skills/data/bun-expert/SKILL.mdBun Expert Skill
You are an expert Bun developer with deep knowledge of the Bun runtime, package manager, test runner, and bundler. You help users build high-performance JavaScript/TypeScript applications using Bun's native APIs and guide migrations from Node.js.
Core Expertise Areas
1. Bun Runtime APIs
HTTP Server & Networking:
- High-performance HTTP/WebSocket server (2.5x faster than Node.js)Bun.serve(options)
- Extended Web Fetch APIBun.fetch(url)
/Bun.connect()
- TCP/UDP socket APIsBun.listen()
- DNS resolution utilitiesBun.dns
File System Operations:
- Returns BunFile (extends Blob) for lazy, zero-copy file operationsBun.file(path)
- Optimized file writesBun.write(path, data)
/Bun.stdin
/Bun.stdout
- Standard I/O streamsBun.stderr
Process & Shell:
/Bun.spawn(cmd)
- Child process spawningBun.spawnSync(cmd)
command`` - Cross-platform shell scripting with template literalsBun.$\- Built-in commands:
,ls
,cd
,rm
,cat
,echo
,pwd
,mkdir
,touch
,whichmv
Data & Storage:
- Built-in SQLite3 driver (3-6x faster than better-sqlite3)bun:sqlite
- Unified SQL API for PostgreSQL, MySQL, SQLiteBun.sql
/Bun.S3Client
- Native S3-compatible storage (5x faster than AWS SDK)Bun.s3
- Built-in Redis clientBun.redis
Utilities:
/Bun.password.hash()
- Argon2 password hashingBun.password.verify()
- Fast hashing (xxhash, murmur)Bun.hash(data)
- Native glob pattern matchingBun.Glob
- Semver comparison utilitiesBun.semver
/Bun.sleep(ms)
- Sleep functionsBun.sleepSync(ms)
- Deep comparisonBun.deepEquals(a, b)
- HTML sanitizationBun.escapeHTML()
/Bun.YAML.parse()
- Native YAML supportBun.YAML.stringify()
- HTML streaming transformationsHTMLRewriter
Advanced Features:
- Foreign Function Interface (2-6x faster than Node.js FFI)bun:ffi
- Web Workers API for multi-threadingWorker
- Pub/sub messaging across threadsBroadcastChannel
- JavaScript/TypeScript transpilation APIBun.Transpiler
- Bundler API with compile supportBun.build()
2. Package Manager Commands
Core Commands:
bun install # Install all dependencies bun install --frozen-lockfile # CI/CD lockfile validation bun add <pkg> # Add dependency bun add -d <pkg> # Add devDependency bun remove <pkg> # Remove dependency bun update # Update outdated packages bun ci # CI-optimized install (--frozen-lockfile) bunx <pkg> # Execute package without installing (100x faster than npx)
Workspace Support:
{ "workspaces": ["packages/*", "apps/*"], "dependencies": { "shared-pkg": "workspace:*" } }
Package Management:
bun pm trust <pkg> # Allow lifecycle scripts bun pm untrusted # View blocked scripts bun why <pkg> # Explain why package installed bun outdated # Show outdated packages bun audit # Security vulnerability check bun patch <pkg> # Prepare package for patching bun link # Link local packages
Lockfile: Bun uses
bun.lock (text-based JSONC format) - human-readable, git-diffable. Automatically migrates from package-lock.json, yarn.lock, or pnpm-lock.yaml.
3. Test Runner (bun:test)
Test Syntax:
import { describe, test, expect, beforeAll, afterEach, mock, spyOn } from "bun:test"; describe("feature", () => { beforeAll(() => { /* setup */ }); afterEach(() => { mock.restore(); }); test("basic assertion", () => { expect(2 + 2).toBe(4); }); test("async operation", async () => { const result = await fetchData(); expect(result).toMatchObject({ status: "ok" }); }); test.each([[1, 2, 3], [2, 3, 5]])("adds %i + %i = %i", (a, b, expected) => { expect(a + b).toBe(expected); }); });
Test Modifiers:
- Skip testtest.skip()
- Run only this test (withtest.only()
flag)--only
- Mark as todotest.todo()
/test.if(condition)
- Conditional executiontest.skipIf(condition)
- Expected to failtest.failing()
- Run concurrentlytest.concurrent
- Retry failed teststest.retry(n)
Key Matchers:
,.toBe()
,.toEqual()
- Equality.toStrictEqual()
,.toContain()
,.toHaveLength()
- String/Array.toMatch()
,.toHaveProperty()
- Objects.toMatchObject()
,.toThrow()
- Errors.rejects.toThrow()
,.toMatchSnapshot()
- Snapshots.toMatchInlineSnapshot()
,.toHaveBeenCalled()
- Mocks.toHaveBeenCalledWith()
Mocking:
import { mock, spyOn } from "bun:test"; const mockFn = mock(() => 42); mockFn.mockImplementation(() => 100); mockFn.mockReturnValue(200); const spy = spyOn(object, "method"); spy.mockResolvedValue({ data: "test" }); // Module mocking mock.module("./api", () => ({ fetchUser: mock(() => ({ id: 1, name: "Test" })) }));
CLI Commands:
bun test # Run all tests bun test --watch # Watch mode bun test --coverage # Enable coverage bun test -t "pattern" # Filter by test name bun test --timeout=5000 # Set timeout bun test --bail # Stop on first failure bun test --update-snapshots # Update snapshots
4. Bundler Configuration
JavaScript API:
const result = await Bun.build({ entrypoints: ["./src/index.tsx"], outdir: "./dist", target: "browser", // "browser" | "bun" | "node" format: "esm", // "esm" | "cjs" | "iife" minify: true, sourcemap: "external", splitting: true, // Code splitting external: ["react", "react-dom"], define: { "process.env.NODE_ENV": '"production"' }, loader: { ".png": "dataurl", ".svg": "text" }, plugins: [myPlugin], naming: { entry: "[dir]/[name].[ext]", chunk: "[name]-[hash].[ext]" } }); if (!result.success) { console.error(result.logs); }
CLI:
bun build ./src/index.tsx --outdir ./dist --minify --sourcemap=external bun build ./src/index.ts --compile --outfile myapp # Single executable
Plugin System:
const myPlugin: BunPlugin = { name: "yaml-loader", setup(build) { build.onLoad({ filter: /\.yaml$/ }, async (args) => { const text = await Bun.file(args.path).text(); return { contents: `export default ${JSON.stringify(YAML.parse(text))}`, loader: "js" }; }); } };
5. TypeScript Integration
Bun executes TypeScript natively without transpilation configuration:
bun run index.ts # Just works bun run index.tsx # JSX supported
Recommended tsconfig.json:
{ "compilerOptions": { "lib": ["ESNext"], "target": "ESNext", "module": "ESNext", "moduleDetection": "force", "moduleResolution": "bundler", "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, "noEmit": true, "strict": true, "skipLibCheck": true, "types": ["bun-types"] } }
Type checking (separate step):
bunx tsc --noEmit
6. Configuration (bunfig.toml)
# Runtime preload = ["./setup.ts"] smol = true # Reduced memory mode # JSX [jsx] runtime = "automatic" importSource = "react" # Package installation [install] optional = false lockfile.save = true [install.scopes] "@myorg" = { url = "https://npm.myorg.com", token = "$NPM_TOKEN" } # Test runner [test] preload = ["./test-setup.ts"] coverage = true coverageThreshold = { lines = 0.8, functions = 0.8 }
7. CLI Flags Reference
Execution:
- Auto-restart on file changes--watch
- Hot module replacement--hot
- Reduced memory mode--smol
/--inspect
- Debugger--inspect-brk
Module Resolution:
/--preload
- Preload modules-r
- Auto-install behavior--install=auto|fallback|force
Transpilation:
/--define
- Compile-time constants-d
- Remove function calls--drop=console
- Custom file loaders--loader
Environment:
- Load specific .env files--env-file
- Set working directory--cwd
/--bun
- Force Bun runtime-b
Node.js Migration Guidance
Quick Migration Steps
- Install Bun:
curl -fsSL https://bun.sh/install | bash - Replace package manager:
# Delete node_modules and lockfile rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml bun install
- Update scripts in package.json:
{ "scripts": { "dev": "bun run --watch src/index.ts", "test": "bun test", "build": "bun build src/index.ts --outdir dist" } }
- Update TypeScript types:
bun add -d @types/bun # Or in tsconfig.json: "types": ["bun-types"]
API Compatibility
Fully Compatible:
,node:assert
,node:buffer
,node:events
,node:pathnode:url
(92%),node:fs
,node:http
,node:https
,node:streamnode:zlib
,node:crypto
,node:net
,node:dnsnode:os
Partially Compatible:
- Missingnode:child_process
,proc.gid
; IPC limited to JSONproc.uid
- Linux-only SO_REUSEPORT for load balancingnode:cluster
- 95% compatible; missingnode:http2pushStream
- Missingnode:worker_threads
,stdin
,stdout
optionsstderr
- AsyncLocalStorage works; v8 promise hooks missingnode:async_hooks
Not Implemented:
,node:inspector
,node:replnode:trace_events
Common Migration Gotchas
- Native Modules: Packages using node-gyp (bcrypt, sharp) may fail
- Solution: Use pure JS alternatives (
instead ofbcryptjs
)bcrypt
- Solution: Use pure JS alternatives (
- Lifecycle Scripts: Bun blocks postinstall by default (security)
- Solution:
or add tobun pm trust <package>trustedDependencies
- Solution:
- Module System: Some packages relying on Node.js internals may fail
doesn't exist in BunModule._nodeModulePaths
- File System Differences: Heavy concurrent file reads can cause memory issues
- Solution: Use
wrappergraceful-fs
- Solution: Use
- TypeScript Entry Points: Update
field for Bun:"main"
{ "main": "src/index.ts" // Not "build/index.js" }
Gradual Migration Strategy
Phase 1: Package manager only (
bun install)
Phase 2: Development tooling (bun run, bun test)
Phase 3: Selective runtime migration (shadow deploy)
Phase 4: Full production migration
Best Practices
Performance Optimization
// Use Bun's native APIs for I/O const file = Bun.file("large.txt"); // Zero-copy const content = await file.text(); await Bun.write("output.txt", processedData); // Use Promise.all for concurrent operations const [users, posts] = await Promise.all([ db.query("SELECT * FROM users"), db.query("SELECT * FROM posts") ]); // Use Bun.serve() static routes Bun.serve({ static: { "/": homepage, "/about": aboutPage }, fetch(req) { /* dynamic routes */ } }); // Use bun:sqlite for local data import { Database } from "bun:sqlite"; const db = new Database(":memory:"); const stmt = db.prepare("SELECT * FROM users WHERE id = ?");
Error Handling
// HTTP server error handling Bun.serve({ fetch(req) { try { return handleRequest(req); } catch (error) { console.error(error); return new Response("Internal Error", { status: 500 }); } }, error(error) { return new Response(`Error: ${error.message}`, { status: 500 }); } }); // Process-level error handling process.on("uncaughtException", (error) => { console.error("Uncaught:", error); process.exit(1); });
Security Best Practices
- Lifecycle Scripts: Keep
minimaltrustedDependencies - Environment Variables: Use
for secrets (not committed).env.local - Input Validation: Sanitize all user inputs
- Dependencies: Run
regularlybun audit - Production: Use
flag to skip devDependencies--production
Project Structure
my-bun-project/ ├── src/ │ ├── index.ts # Entry point │ ├── server.ts # HTTP server │ └── lib/ # Utilities ├── test/ │ └── *.test.ts # Test files ├── bunfig.toml # Bun configuration ├── tsconfig.json # TypeScript config ├── package.json └── .env.local # Local secrets (gitignored)
Debugging
Web Debugger:
bun --inspect server.ts # Start debugger bun --inspect-brk server.ts # Break at first line bun --inspect-wait server.ts # Wait for connection
Open
https://debug.bun.sh or use VSCode Bun extension.
Verbose Fetch Logging:
BUN_CONFIG_VERBOSE_FETCH=curl bun run server.ts
Examples
HTTP Server with WebSocket
Bun.serve({ port: 3000, fetch(req, server) { if (server.upgrade(req)) return; return new Response("Hello Bun!"); }, websocket: { open(ws) { console.log("Connected"); }, message(ws, message) { ws.send(`Echo: ${message}`); }, close(ws) { console.log("Disconnected"); } } });
File Server
Bun.serve({ async fetch(req) { const path = new URL(req.url).pathname; const file = Bun.file(`./public${path}`); if (await file.exists()) { return new Response(file); } return new Response("Not Found", { status: 404 }); } });
Database with SQLite
import { Database } from "bun:sqlite"; const db = new Database("app.db"); db.run(`CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE )`); const insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)"); const getAll = db.prepare("SELECT * FROM users"); insert.run("Alice", "alice@example.com"); const users = getAll.all();
When This Skill Activates
This skill automatically activates when:
- Working with
,.ts
,.tsx
,.js
files in a Bun project.jsx - Creating or modifying
orbunfig.tomlbun.lock - Using
,bun:test
,bun:sqlite
importsbun:ffi - Discussing Bun APIs (Bun.serve, Bun.file, Bun.build)
- Migrating from Node.js to Bun
- Writing or debugging Bun tests
- Configuring the Bun bundler