From fieldguides
This skill should be used when working with Bun runtime, bun:sqlite, Bun.serve, bun:test, or when Bun, bun:test, or Bun-specific patterns are mentioned.
How this skill is triggered — by the user, by Claude, or both
Slash command
/fieldguides:bun-fieldguideThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Bun runtime → native APIs → zero-dependency patterns.
Bun runtime → native APIs → zero-dependency patterns.
<when_to_use>
NOT for: Node.js-only patterns, cross-runtime libraries, non-Bun projects
</when_to_use>
<runtime_basics>
Package management:
bun install # Install deps
bun add zod # Add package
bun remove zod # Remove package
bun update # Update all
Script execution:
bun run dev # Run package.json script
bun run src/index.ts # Execute TypeScript directly
bun --watch index.ts # Watch mode
Testing:
bun test # All tests
bun test src/ # Directory
bun test --watch # Watch mode
bun test --coverage # With coverage
Building:
bun build ./index.ts --outfile dist/bundle.js
bun build ./index.ts --compile --outfile myapp # Standalone executable
</runtime_basics>
<file_operations>
// Read file (lazy, efficient)
const file = Bun.file("./data.json");
if (!(await file.exists())) throw new Error("File not found");
// Read formats
const text = await file.text();
const json = await file.json();
const buffer = await file.arrayBuffer();
const stream = file.stream(); // Large files
// Metadata
console.log(file.size, file.type);
// Write
await Bun.write("./output.txt", "content");
await Bun.write("./data.json", JSON.stringify(data));
await Bun.write("./blob.txt", new Blob(["data"]));
</file_operations>
import { Database } from "bun:sqlite";
const db = new Database("app.db", {
create: true,
readwrite: true,
strict: true,
});
// Create tables
db.run(`
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
)
`);
// Prepared statements (always use these)
const getUser = db.prepare("SELECT * FROM users WHERE id = ?");
const createUser = db.prepare(
"INSERT INTO users (id, email, name) VALUES (?, ?, ?) RETURNING *"
);
// Execution
const user = getUser.get("user-123"); // Single row
const all = db.prepare("SELECT * FROM users").all(); // All rows
db.prepare("DELETE FROM users WHERE id = ?").run("id"); // No return
// Named parameters
const stmt = db.prepare("SELECT * FROM users WHERE email = $email");
stmt.get({ $email: "[email protected]" });
// Transactions (atomic, auto-rollback on error)
const transfer = db.transaction(
(fromId: string, toId: string, amount: number) => {
db.run("UPDATE accounts SET balance = balance - ? WHERE id = ?", [
amount,
fromId,
]);
db.run("UPDATE accounts SET balance = balance + ? WHERE id = ?", [
amount,
toId,
]);
}
);
transfer("alice", "bob", 100);
db.close(); // When done
See sqlite-patterns.md for migrations, pooling, repository pattern.
// Hash (argon2id recommended)
const hash = await Bun.password.hash("password123", {
algorithm: "argon2id",
memoryCost: 65536, // 64 MB
timeCost: 3,
});
// Or bcrypt
const bcryptHash = await Bun.password.hash("password123", {
algorithm: "bcrypt",
cost: 12,
});
// Verify
const isValid = await Bun.password.verify("password123", hash);
if (!isValid) throw new Error("Invalid password");
Auth flow example:
app.post("/auth/register", zValidator("json", RegisterSchema), async (c) => {
const { email, password } = c.req.valid("json");
const db = c.get("db");
if (db.prepare("SELECT id FROM users WHERE email = ?").get(email)) {
throw new HTTPException(409, { message: "Email already registered" });
}
const hashedPassword = await Bun.password.hash(password, {
algorithm: "argon2id",
});
const user = db
.prepare(
`
INSERT INTO users (id, email, password) VALUES (?, ?, ?) RETURNING id, email
`
)
.get(crypto.randomUUID(), email, hashedPassword);
return c.json({ user }, 201);
});
<http_server>
Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/") return new Response("Hello");
if (url.pathname === "/json") return Response.json({ ok: true });
return new Response("Not found", { status: 404 });
},
error(err) {
return new Response(`Error: ${err.message}`, { status: 500 });
},
});
With Hono (recommended for APIs):
import { Hono } from "hono";
const app = new Hono()
.get("/", (c) => c.text("Hello"))
.get("/json", (c) => c.json({ ok: true }));
Bun.serve({ port: 3000, fetch: app.fetch });
See server-patterns.md for routing, middleware, file serving, streaming.
</http_server>
import type { ServerWebSocket } from "bun";
type WsData = { userId: string };
Bun.serve<WsData>({
port: 3000,
fetch(req, server) {
const url = new URL(req.url);
if (url.pathname === "/ws") {
const userId = url.searchParams.get("userId") || "anon";
return server.upgrade(req, { data: { userId } })
? undefined
: new Response("Upgrade failed", { status: 400 });
}
return new Response("Hello");
},
websocket: {
open(ws: ServerWebSocket<WsData>) {
ws.subscribe("chat");
ws.send(JSON.stringify({ type: "connected" }));
},
message(ws: ServerWebSocket<WsData>, msg: string | Buffer) {
ws.publish("chat", msg);
},
close(ws: ServerWebSocket<WsData>) {
ws.unsubscribe("chat");
},
},
});
See server-patterns.md for client tracking, rooms, reconnection.
import { $ } from "bun";
// Run commands
const result = await $`ls -la`;
console.log(result.text());
// Variables (auto-escaped)
const dir = "./src";
await $`find ${dir} -name "*.ts"`;
// Check exit code
const { exitCode } = await $`npm test`.nothrow();
if (exitCode !== 0) console.error("Tests failed");
// Spawn process
const proc = Bun.spawn(["ls", "-la"]);
await proc.exited;
// Capture output
const proc2 = Bun.spawn(["echo", "Hello"], { stdout: "pipe" });
const output = await new Response(proc2.stdout).text();
import { describe, test, expect, beforeEach, afterEach } from "bun:test";
describe("feature", () => {
let db: Database;
beforeEach(() => {
db = new Database(":memory:");
});
afterEach(() => {
db.close();
});
test("behavior", () => {
expect(result).toBe(expected);
expect(arr).toContain(item);
expect(fn).toThrow();
expect(obj).toEqual({ foo: "bar" });
});
test("async", async () => {
const result = await asyncFn();
expect(result).toBeDefined();
});
test.todo("pending feature");
test.skip("temporarily disabled");
});
bun test # All tests
bun test src/api.test.ts # Specific file
bun test --watch # Watch mode
bun test --coverage # With coverage
See testing.md for assertions, mocking, snapshots, best practices.
// Access
console.log(Bun.env.NODE_ENV);
console.log(Bun.env.DATABASE_URL);
// Zod validation
import { z } from "zod";
const EnvSchema = z.object({
NODE_ENV: z
.enum(["development", "production", "test"])
.default("development"),
DATABASE_URL: z.string(),
PORT: z.coerce.number().int().positive().default(3000),
API_KEY: z.string().min(32),
});
export const env = EnvSchema.parse(Bun.env);
Bun auto-loads .env, .env.local, .env.production.
// High-resolution timing
const start = Bun.nanoseconds();
await doWork();
console.log(`Took ${(Bun.nanoseconds() - start) / 1_000_000}ms`);
// Hashing
const hash = Bun.hash(data);
const crc32 = Bun.hash.crc32(data);
const sha256 = Bun.CryptoHasher.hash("sha256", data);
// Sleep
await Bun.sleep(1000);
// Memory
const { rss, heapUsed } = process.memoryUsage();
console.log("RSS:", rss / 1024 / 1024, "MB");
# Production bundle
bun build ./index.ts --outfile dist/bundle.js --minify --sourcemap
# External deps
bun build ./index.ts --outfile dist/bundle.js --external hono --external zod
# Standalone executable
bun build ./index.ts --compile --outfile myapp
# Cross-compile
bun build ./index.ts --compile --target=bun-linux-x64 --outfile myapp-linux
bun build ./index.ts --compile --target=bun-darwin-arm64 --outfile myapp-macos
bun build ./index.ts --compile --target=bun-windows-x64 --outfile myapp.exe
ALWAYS:
NEVER:
PREFER:
Examples:
Level up: Load the bun-first skill for migration auditing, dependency elimination, and the decision framework for when to use Bun native APIs over npm packages.
npx claudepluginhub outfitter-dev/outfitter --plugin fieldguidesBun runtime conventions, APIs, and toolchain. Invoke whenever task involves any interaction with Bun — serving HTTP, file I/O, shell scripting, testing, bundling, or package management with Bun.
Guides Bun runtime setup, project initialization, and migration from Node.js. Useful for faster JS/TS development with Bun's built-in bundler, test runner, and native TypeScript support.
Provides guidance and examples for Bun runtime APIs including Bun.file(), Bun.serve(), WebSockets, environment variables, and shell execution in JS/TS projects.