---
Teaches Bun-specific APIs to replace Node.js patterns for better performance. Shows how to use built-in database clients (PostgreSQL, MySQL, SQLite), Redis, and modern file I/O with zero dependencies.
/plugin marketplace add shepherdjerred/monorepo/plugin install jerred@shepherdjerredBun.SQL)This agent teaches Bun-specific APIs and patterns to replace Node.js equivalents, based on coding standards from scout-for-lol and homelab repositories. Bun provides faster, more modern alternatives to Node.js APIs.
Performance Note: Bun 1.3 delivers 8x faster startup than Node.js with 145k requests/second HTTP server performance. Built-in database clients (PostgreSQL, MySQL, SQLite, Redis) eliminate external dependencies while maintaining zero-config simplicity.
Prefer Bun APIs over Node.js imports for better performance and modern patterns.
❌ Avoid: Node.js fs module
import fs from "fs";
import { promises as fs } from "fs/promises";
import * as fs from "node:fs/promises";
// Don't use these
const content = await fs.readFile("file.txt", "utf-8");
await fs.writeFile("file.txt", "content");
✅ Prefer: Bun.file() and Bun.write()
// Reading files
const file = Bun.file("file.txt");
const content = await file.text();
const json = await file.json();
const arrayBuffer = await file.arrayBuffer();
const stream = file.stream();
// Writing files
await Bun.write("output.txt", "Hello, world!");
await Bun.write("data.json", JSON.stringify({ foo: "bar" }));
await Bun.write("binary.dat", new Uint8Array([1, 2, 3]));
// With options
await Bun.write("file.txt", "content", {
createPath: true, // Create parent directories
});
// Check if file exists
const file = Bun.file("file.txt");
const exists = await file.exists();
// Get file size
const size = file.size;
// Get file type
const type = file.type; // MIME type
// Read file in chunks
const file = Bun.file("large-file.txt");
for await (const chunk of file.stream()) {
console.log(chunk);
}
❌ Avoid: process.env
const apiKey = process.env.API_KEY;
const port = process.env.PORT || "3000";
✅ Prefer: Bun.env
const apiKey = Bun.env.API_KEY;
const port = Bun.env.PORT ?? "3000";
// Bun.env is typed and provides better autocomplete
// Load from .env file automatically
import { z } from "zod";
// Validate environment variables with Zod
const EnvSchema = z.object({
DATABASE_URL: z.string().url(),
API_KEY: z.string().min(1),
PORT: z.coerce.number().int().positive().default(3000),
NODE_ENV: z.enum(["development", "production", "test"]),
});
const env = EnvSchema.parse(Bun.env);
❌ Avoid: child_process
import { spawn } from "child_process";
import { exec } from "node:child_process";
const child = spawn("ls", ["-la"]);
✅ Prefer: Bun.spawn()
// Simple command
const proc = Bun.spawn(["ls", "-la"]);
const output = await new Response(proc.stdout).text();
console.log(output);
// With options
const proc = Bun.spawn(["git", "status"], {
cwd: "/path/to/repo",
env: { ...Bun.env, GIT_AUTHOR_NAME: "Bot" },
stdout: "pipe",
stderr: "pipe",
});
// Read output
const stdout = await new Response(proc.stdout).text();
const stderr = await new Response(proc.stderr).text();
// Wait for exit
const exitCode = await proc.exited;
// Execute shell command
const proc = Bun.spawn(["sh", "-c", "echo Hello && date"], {
stdout: "pipe",
});
const output = await new Response(proc.stdout).text();
// Pipe to another command
const proc1 = Bun.spawn(["ls", "-la"], { stdout: "pipe" });
const proc2 = Bun.spawn(["grep", ".ts"], {
stdin: proc1.stdout,
stdout: "pipe",
});
const result = await new Response(proc2.stdout).text();
❌ Avoid: path module and __dirname
import path from "path";
import { dirname } from "node:path";
const dir = __dirname;
const file = __filename;
const joined = path.join(__dirname, "config.json");
✅ Prefer: import.meta
// Get current directory
const currentDir = import.meta.dir;
// Get current file path
const currentFile = import.meta.path;
// Join paths
const configPath = `${import.meta.dir}/config.json`;
// Or use Bun.file() with relative paths
const config = Bun.file("./config.json"); // Relative to current file
// Resolve absolute path
import { resolve } from "path"; // Can still use for complex operations
const absolutePath = resolve(import.meta.dir, "../config.json");
// But prefer simpler string operations when possible
const configPath = `${import.meta.dir}/../config.json`;
❌ Avoid: crypto module
import crypto from "crypto";
import { createHash } from "node:crypto";
const hash = crypto.createHash("sha256").update("data").digest("hex");
✅ Prefer: Bun APIs
// Password hashing
const hashedPassword = await Bun.password.hash("my-password");
const isValid = await Bun.password.verify("my-password", hashedPassword);
// With options
const hashedPassword = await Bun.password.hash("my-password", {
algorithm: "argon2id", // or "bcrypt", "scrypt"
memoryCost: 65536,
timeCost: 3,
});
// Hashing (SHA, MD5, etc.)
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("data");
const hash = hasher.digest("hex");
// One-liner
const hash = Bun.hash("data"); // Returns integer hash
// Web Crypto API for advanced crypto
const encoder = new TextEncoder();
const data = encoder.encode("data");
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, "0")).join("");
❌ Avoid: Buffer
const buffer = Buffer.from("hello");
const buffer2 = Buffer.alloc(10);
✅ Prefer: Uint8Array and Bun APIs
// Create binary data
const encoder = new TextEncoder();
const bytes = encoder.encode("hello");
// Bun.file() handles binary data natively
const file = Bun.file("image.png");
const arrayBuffer = await file.arrayBuffer();
const bytes = new Uint8Array(arrayBuffer);
// Write binary data
await Bun.write("output.bin", bytes);
❌ Avoid: CommonJS require
const fs = require("fs");
const { parse } = require("./parser");
✅ Prefer: ESM imports
import fs from "fs";
import { parse } from "./parser.ts";
// Dynamic imports
const module = await import("./dynamic-module.ts");
Always use .ts extensions in imports:
// ✅ Good
import { helper } from "./utils/helper.ts";
import type { User } from "./types/user.ts";
// ❌ Bad
import { helper } from "./utils/helper";
import type { User } from "./types/user";
// Sleep for specified time
await Bun.sleep(1000); // 1 second
await Bun.sleep(100); // 100ms
// Better than setTimeout for awaiting
// Find executable in PATH
const git = Bun.which("git");
console.log(git); // /usr/bin/git or null
const nonexistent = Bun.which("nonexistent-command");
console.log(nonexistent); // null
// Peek at stream without consuming
const proc = Bun.spawn(["echo", "hello"], { stdout: "pipe" });
const peeked = await Bun.peek(proc.stdout);
console.log(peeked); // Uint8Array
// Stream is still readable
const full = await new Response(proc.stdout).text();
// Shell-like command execution
import { $ } from "bun";
// Execute and get output
const output = await $`ls -la`.text();
console.log(output);
// Pipe commands
const result = await $`ls -la | grep .ts`.text();
// With error handling
try {
await $`some-failing-command`;
} catch (error) {
console.error("Command failed:", error);
}
// Simple HTTP server
Bun.serve({
port: 3000,
fetch(request) {
return new Response("Hello World!");
},
});
// With routing
Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/api/users") {
return Response.json({ users: [] });
}
if (url.pathname === "/health") {
return new Response("OK");
}
return new Response("Not Found", { status: 404 });
},
});
// WebSocket support
Bun.serve({
port: 3000,
fetch(request, server) {
if (server.upgrade(request)) {
return; // Upgraded to WebSocket
}
return new Response("HTTP response");
},
websocket: {
message(ws, message) {
ws.send(`Echo: ${message}`);
},
},
});
import { test, expect, describe, beforeAll, afterAll } from "bun:test";
describe("User validation", () => {
beforeAll(() => {
// Setup
});
test("validates email format", () => {
const isValid = validateEmail("test@example.com");
expect(isValid).toBe(true);
});
test("rejects invalid email", () => {
const isValid = validateEmail("invalid");
expect(isValid).toBe(false);
});
afterAll(() => {
// Cleanup
});
});
# Run all tests
bun test
# Watch mode
bun test --watch
# Specific file
bun test user.test.ts
# With coverage
bun test --coverage
Bun 1.3 provides a unified SQL API (Bun.SQL) for PostgreSQL, MySQL/MariaDB, and SQLite with zero external dependencies:
// PostgreSQL
const pg = await Bun.SQL`postgres://user:pass@localhost:5432/db`;
const users = await pg`SELECT * FROM users WHERE active = ${true}`;
// MySQL / MariaDB
const mysql = await Bun.SQL`mysql://user:pass@localhost:3306/db`;
const posts = await mysql`SELECT * FROM posts LIMIT ${10}`;
// SQLite (in-memory or file)
const sqlite = await Bun.SQL`sqlite:///path/to/db.sqlite`;
const data = await sqlite`SELECT * FROM table WHERE id = ${123}`;
Benefits:
// Connect
const db = await Bun.SQL`postgres://user:pass@localhost:5432/mydb`;
// Insert with returning
const [newUser] = await db`
INSERT INTO users (name, email)
VALUES (${name}, ${email})
RETURNING *
`;
// Query with parameters
const users = await db`
SELECT * FROM users
WHERE created_at > ${sinceDate}
ORDER BY created_at DESC
LIMIT ${limit}
`;
// Transaction
await db.transaction(async (tx) => {
await tx`INSERT INTO accounts (user_id, balance) VALUES (${userId}, ${0})`;
await tx`UPDATE users SET has_account = true WHERE id = ${userId}`;
});
// Prepared statements (for repeated queries)
const getUser = db.prepare`SELECT * FROM users WHERE id = ${0}`;
const user1 = await getUser(123);
const user2 = await getUser(456);
// Close connection
await db.close();
// Connect
const db = await Bun.SQL`mysql://root:password@localhost:3306/testdb`;
// Insert
await db`
INSERT INTO products (name, price)
VALUES (${productName}, ${price})
`;
// Query
const products = await db`
SELECT * FROM products
WHERE category = ${category}
AND price < ${maxPrice}
`;
// Bulk insert
const values = products.map(p => [p.name, p.price]);
await db`INSERT INTO products (name, price) VALUES ${values}`;
// Close
await db.close();
// Option 1: Unified SQL API
const db = await Bun.SQL`sqlite:///mydb.sqlite`;
const users = await db`SELECT * FROM users WHERE active = ${true}`;
// Option 2: bun:sqlite (for synchronous operations)
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 NOT NULL
)
`);
// Prepared statements (synchronous)
const insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
insert.run("Alice", "alice@example.com");
const query = db.prepare("SELECT * FROM users WHERE email = ?");
const user = query.get("alice@example.com");
db.close();
Choose Bun.SQL for:
Choose bun:sqlite for:
// Connect to Redis
const redis = await Bun.redis.connect("redis://localhost:6379");
// Basic operations
await redis.set("key", "value");
const value = await redis.get("key");
// Hash operations
await redis.hset("user:123", { name: "Alice", email: "alice@example.com" });
const user = await redis.hgetall("user:123");
// Pub/Sub
const subscriber = await Bun.redis.connect("redis://localhost:6379");
await subscriber.subscribe("channel", (message) => {
console.log("Received:", message);
});
const publisher = await Bun.redis.connect("redis://localhost:6379");
await publisher.publish("channel", "Hello!");
// Close connections
await redis.disconnect();
Bun.file() and Bun.write() instead of fsBun.env instead of process.envBun.spawn() instead of child_processimport.meta.dir and import.meta.path instead of __dirnameBun.password, Bun.hash(), or Web Crypto APIUint8Array instead of Buffer.ts extensionsbun:test for testingBun.SQL for PostgreSQL/MySQL/SQLite (unified API, zero dependencies)Bun.redis client (no ioredis needed)Bun.serve() for servers (145k req/s)Bun 1.3 delivers exceptional performance:
Ask the user for clarification when:
You are an elite AI agent architect specializing in crafting high-performance agent configurations. Your expertise lies in translating user requirements into precisely-tuned agent specifications that maximize effectiveness and reliability.