Bunintermediate
import { write } from "bun";
export const saveJsonReport = (path: string, report: Record<string, unknown>) =>
write(path, JSON.stringify(report, null, 2) + "\n");
Write files in Bun without extra dependencies or shelling out.
Bunintermediate
import { beforeEach, afterEach, test, expect } from "bun:test";
import { file } from "bun";
import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
Keep Bun tests small by extracting repeated setup into a fixture helper.
Bunadvanced
const transpiler = new Bun.Transpiler({ loader: "tsx" });
const source = `
interface Props { name: string }
export const Greeting = (props: Props) => <h1>Hello, {props.name}!</h1>;
Bun.Transpiler exposes Bun's own TS/JSX-to-JS compiler as a callable class, for transforming source strings at runtime without shelling out to a build step.
Bunadvanced
export const countPrimesOnWorker = (from: number, to: number) => {
const workerCode = `
self.onmessage = ({ data: [from, to] }) => {
let count = 0;
for (let n = from; n < to; n++) {
Bun's Worker API uses real OS threads, so CPU-bound work can be split across workers created from an in-memory blob: URL, with no separate worker file needed.
Bunintermediate
const measureColdStart = (cmd: string[]) => {
const start = performance.now();
Bun.spawnSync(cmd);
return performance.now() - start;
};
Bun.spawnSync plus performance.now() around each call turns a cold-start comparison against Node into a five-line, dependency-free benchmark.
Bunintermediate
import { serve, file } from "bun";
const PUBLIC_DIR = `${import.meta.dir}/public`;
const server = serve({
A fetch handler can serve API routes first and fall back to Bun.file for anything else, building a static file server without a separate static-file middleware.
Bunadvanced
import { dlopen, FFIType, suffix } from "bun:ffi";
const path = `libsqlite3.${suffix}`;
const { symbols } = dlopen(path, {
bun:ffi's dlopen loads a shared library and JIT-compiles a JS-to-native binding for each symbol, letting Bun call C functions directly with no N-API glue code.
Bunintermediate
declare module "bun" {
interface Env {
DATABASE_URL: string;
DEBUG?: string;
}
Bun parses .env, .env.local, and .env.production automatically before your code runs, so import 'dotenv/config' is not just unnecessary but dead weight.
Bunintermediate
declare global {
var server: ReturnType<typeof Bun.serve> | undefined;
var reloadCount: number;
}
bun --hot re-evaluates changed files without restarting the process, so an HTTP server's listener survives a save instead of dropping every open connection.
Bunadvanced
const proc = Bun.spawn(["bun", "-e", "console.log((await Bun.stdin.text()).toUpperCase())"], {
stdin: "pipe",
});
proc.stdin.write("hello from the parent\n");
Bun.spawn's stdin/stdout are a FileSink and a ReadableStream, so you can write to a child process incrementally and read its output as it streams back.
Bunintermediate
export const wsServer = Bun.serve({
fetch(req, server) {
return server.upgrade(req) ? undefined : new Response("Upgrade failed", { status: 500 });
},
websocket: {
Bun.serve() upgrades an HTTP request to a WebSocket in the fetch handler and reuses one handler object across every connection, no ws package needed.
Bunadvanced
try {
const result = await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
minify: true,
Bun.build() is the bun build CLI as a JS function, returning artifacts you can inspect, write, or serve directly instead of shelling out.
Bunintermediate
export const hashPassword = (password: string) =>
Bun.password.hash(password, { algorithm: "argon2id", memoryCost: 19456, timeCost: 2 });
export const verifyPassword = (password: string, hash: string) => Bun.password.verify(password, hash);
Bun.password.hash and .verify wrap argon2 and bcrypt natively, so hashing a password needs no bcrypt or argon2 npm package at all.
Bunintermediate
import { test, expect } from "bun:test";
const formatInvoice = (id: number, cents: number) => ({
id,
total: `$${(cents / 100).toFixed(2)}`,
toMatchSnapshot() saves a value's serialized shape on first run and diffs it on every run after, catching output changes you didn't write assertions for.
Bunintermediate
import { $ } from "bun";
await $`rm -rf dist`;
await $`mkdir dist`;
Bun's $ template literal runs a small bash-like shell with no /bin/sh dependency, so build scripts behave identically on Windows, macOS, and Linux.
Bunintermediate
import { serve, file } from "bun";
const server = serve({
async fetch(req) {
const pathname = new URL(req.url).pathname;
Bun.file() returns a lazy file handle that streams straight into a Response, so serving a large file never buffers it fully in memory.
Bunintermediate
import { Database } from "bun:sqlite";
const db = new Database(":memory:");
db.exec(`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)`);
bun:sqlite ships inside the Bun binary with a synchronous, prepared-statement API, so a local database needs zero npm installs.
Bunintermediate
export const app = Bun.serve({
routes: {
"/api/health": new Response("ok"),
"/api/users/:id": (req) => Response.json({ id: req.params.id }),
"/api/users": {
Bun.serve()'s routes option matches paths, HTTP methods, and :params natively, replacing a router dependency for most REST APIs.