| name | bun-dev |
| version | 1.0.0 |
| description | Bun runtime patterns including native APIs, SQLite, testing, HTTP server, WebSocket, file handling, and shell operations. Use when working with Bun runtime, bun:sqlite, Bun.serve, bun:test, or when Bun, --bun flag, SQLite, or Bun-specific patterns mentioned. |
Bun Development
Bun runtime → native APIs → zero-dependency patterns.
<when_to_use>
- Bun runtime development
- SQLite database with bun:sqlite
- HTTP server with Bun.serve
- Testing with bun:test
- File operations with Bun.file/Bun.write
- Shell operations with $ template
- Password hashing with Bun.password
- Environment variable handling
- Building and bundling
NOT for: Node.js-only patterns, cross-runtime libraries, non-Bun projects
</when_to_use>
<runtime_basics>
Package management:
bun install
bun add zod
bun remove zod
bun update
Script execution:
bun run dev
bun run src/index.ts
bun --watch index.ts
Testing:
bun test
bun test src/
bun test --watch
bun test --coverage
Building:
bun build ./index.ts --outfile dist/bundle.js
bun build ./index.ts --compile --outfile myapp
</runtime_basics>
File Operations
<file_operations>
const file = Bun.file('./data.json');
if (!(await file.exists())) {
throw new Error('File not found');
}
const text = await file.text();
const json = await file.json();
const buffer = await file.arrayBuffer();
const stream = file.stream();
console.log(file.size);
console.log(file.type);
await Bun.write('./output.txt', 'content');
await Bun.write('./data.json', JSON.stringify(data));
const blob = new Blob([], { : });
.(, blob);
readable = ({ ... });
.(, readable);
</file_operations>
SQLite (bun:sqlite)
import { Database } from 'bun:sqlite';
const db = new Database('app.db', {
create: true,
readwrite: true,
strict: true
});
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
)
`);
const getUser = db.prepare('SELECT * FROM users WHERE id = ?');
const createUser = db.prepare('INSERT INTO users (id, email, name) VALUES (?, ?, ?) RETURNING *');
const updateUser = db.prepare('UPDATE users SET email = ?, name = ? WHERE id = ? RETURNING *');
const deleteUser = db.prepare('DELETE FROM users WHERE id = ? RETURNING *');
const user = getUser.get('user-123');
const allUsers = db.prepare('SELECT * FROM users').all();
db.prepare('DELETE FROM users WHERE id = ?').run('user-123');
stmt = db.();
user = stmt.(, );
stmt2 = db.();
user2 = stmt2.({ : });
transfer = db.( {
db.(, [amount, fromId]);
db.(, [amount, toId]);
});
(, , );
db.();
See sqlite-patterns.md for migrations and advanced patterns.
Password Hashing
const hashedPassword = await Bun.password.hash('password123', {
algorithm: 'argon2id',
memoryCost: 65536,
timeCost: 3
});
const bcryptHash = await Bun.password.hash('password123', {
algorithm: 'bcrypt',
cost: 12
});
const isValid = await Bun.password.verify('password123', hashedPassword);
if (!isValid) {
throw new Error('Invalid password');
}
In auth flow:
app.post('/auth/register', zValidator('json', RegisterSchema), async (c) => {
const { email, password } = c.req.valid('json');
const db = c.get('db');
const existing = db.prepare('SELECT id FROM users WHERE email = ?').get(email);
if (existing) {
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
<http_server>
Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === '/') {
return new Response('Hello, world!');
}
if (url.pathname === '/json') {
return Response.json({ message: 'Hello' });
}
return new Response('Not found', { status: 404 });
},
error(err) {
return new Response(`Error: ${err.message}`, { status: 500 });
}
});
console.log('Server running on http://localhost:3000');
With Hono (recommended for complex 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
});
</http_server>
WebSocket
import type { ServerWebSocket } from 'bun';
type WebSocketData = { userId: string };
Bun.serve<WebSocketData>({
port: 3000,
fetch(req, server) {
const url = new URL(req.url);
if (url.pathname === '/ws') {
const userId = url.searchParams.get('userId') || 'anonymous';
const success = server.upgrade(req, { data: { userId } });
if (!success) {
return new Response('WebSocket upgrade failed', { status: 400 });
}
return undefined;
}
return new Response('Hello');
},
websocket: {
open(ws: ServerWebSocket<WebSocketData>) {
console.log();
ws.();
ws.(.({ : }));
},
() {
.(, message);
ws.(, message);
},
() {
.();
ws.();
}
}
});
Shell Operations
import { $ } from 'bun';
const result = await $`ls -la`;
console.log(result.text());
const dir = './src';
await $`find ${dir} -name "*.ts"`;
const { exitCode } = await $`npm test`.nothrow();
if (exitCode !== 0) {
console.error('Tests failed');
}
const proc = Bun.spawn(['ls', '-la']);
await proc.exited;
console.log('Exit code:', proc.exitCode);
const proc2 = Bun.spawn(['echo', 'Hello'], { stdout: 'pipe' });
const output = await new Response(proc2.stdout).text();
Testing (bun:test)
import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach } from 'bun:test';
describe('feature', () => {
let db: Database;
beforeAll(() => {
console.log('Setup test suite');
});
afterAll(() => {
console.log('Cleanup test suite');
});
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' });
expect(value).toBeDefined();
expect(value).toBeTruthy();
});
test('async behavior', async () => {
const result = ();
(result).();
});
test.();
test.();
});
Run tests:
bun test
bun test src/api.test.ts
bun test --watch
bun test --coverage
Environment Variables
console.log(Bun.env.NODE_ENV);
console.log(Bun.env.DATABASE_URL);
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)
});
const env = EnvSchema.parse(Bun.env);
export default env;
Bun automatically loads .env files:
DATABASE_URL=sqlite://app.db
PORT=3000
Compression
import { gzipSync, gunzipSync, deflateSync, inflateSync } from 'bun';
const data = 'Large data string...'.repeat(1000);
const compressed = gzipSync(data);
const decompressed = gunzipSync(compressed);
const deflated = deflateSync('data');
const inflated = inflateSync(deflated);
app.get('/large-data', (c) => {
const data = generateLargeDataset();
const json = JSON.stringify(data);
const acceptEncoding = c.req.header('accept-encoding') || '';
if (acceptEncoding.includes('gzip')) {
const compressed = gzipSync(json);
return c.body(compressed, {
headers: {
'Content-Type': 'application/json',
'Content-Encoding': 'gzip'
}
});
}
return c.json(data);
});
Performance Utilities
const start = Bun.nanoseconds();
await doWork();
const elapsed = Bun.nanoseconds() - start;
console.log(`Took ${elapsed / 1_000_000}ms`);
const hash = Bun.hash(data);
const crc32 = Bun.hash.crc32(data);
const sha256 = Bun.CryptoHasher.hash('sha256', data);
await Bun.sleep(1000);
const usage = process.memoryUsage();
console.log('RSS:', usage.rss / 1024 / 1024, 'MB');
console.log('Heap Used:', usage.heapUsed / 1024 / 1024, 'MB');
Building & Bundling
bun build ./index.ts --outfile dist/bundle.js --minify --sourcemap
bun build ./index.ts --outfile dist/bundle.js --external hono --external zod
bun build ./index.ts --compile --outfile myapp
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:
- Use Bun APIs when available (faster, native)
- Prepared statements for database queries
- Transactions for multi-statement operations
- argon2id for password hashing
- Validate environment variables at startup
- Close database connections when done
NEVER:
- String interpolation in SQL queries (use parameters)
- Store plaintext passwords
- Ignore async disposal cleanup
- Use deprecated Node.js APIs when Bun native exists
PREFER:
- Bun.file over fs.readFile
- Bun.write over fs.writeFile
- bun:sqlite over external SQLite libraries
- Bun.password over bcrypt/argon2 packages
- $ shell template over child_process
Examples: