Claude Code for Bun: Fast JavaScript Runtime and Toolkit — Claude Skills 360 Blog
Blog / Backend / Claude Code for Bun: Fast JavaScript Runtime and Toolkit
Backend

Claude Code for Bun: Fast JavaScript Runtime and Toolkit

Published: June 13, 2027
Read time: 6 min read
By: Claude Skills 360

Bun is an all-in-one JavaScript runtime, bundler, and package manager — Bun.serve({ fetch(req) { return new Response("Hello") } }) starts an HTTP server. Bun.file("path.json") reads files with .text(), .json(), .arrayBuffer(), or .stream(). Bun.$\ls -la`runs shell commands.import { Database } from “bun:sqlite”provides SQLite.bun:testexportsdescribe, it, expect, mock, spyOn. Bun.build({ entrypoints: [“src/index.ts”], outdir: “dist” })bundles TypeScript.Bun.password.hash(pwd)hashes passwords with bcrypt or argon2.Bun.CryptoHasherprovides SHA-256/SHA-512 hashing.Bun.servesupports HTTP/2, WebSocket withws.send()/ws.close(), and TLS. bun —hothot-reloads without restart. Bun is Node.js-compatible —npm installworks viabun install. Bun.sql` provides native PostgreSQL connection pooling. Claude Code generates Bun HTTP servers, SQLite databases, bundling configs, and test suites.

CLAUDE.md for Bun

## Bun Stack
- Version: bun >= 1.1
- Server: Bun.serve({ port: 3000, fetch: async (req) => new Response(body, { headers }) })
- File: const file = Bun.file("./data.json"); const data = await file.json()
- Write: await Bun.write("output.txt", content)
- Shell: const output = await Bun.$`cat package.json`.json()
- SQLite: import { Database } from "bun:sqlite"; const db = new Database("app.db")
- Test: import { describe, it, expect, mock } from "bun:test"
- Build: Bun.build({ entrypoints: ["./src/index.ts"], outdir: "./dist", target: "bun" })
- Hash: const hash = Bun.hash("string") — FNV hash; for cryptographic: new Bun.CryptoHasher("sha256")

HTTP Server

// src/server.ts — Bun HTTP server with routing
import { type Server } from "bun"
import { handleAuth } from "./routes/auth"
import { handlePosts } from "./routes/posts"
import { handleStatic } from "./routes/static"

type Handler = (req: Request, params: Record<string, string>) => Promise<Response> | Response

// Simple router
const routes: Array<{
  method: string
  pattern: URLPattern
  handler: Handler
}> = [
  { method: "GET", pattern: new URLPattern({ pathname: "/health" }), handler: handleHealth },
  { method: "GET", pattern: new URLPattern({ pathname: "/api/posts" }), handler: handlePosts.list },
  { method: "POST", pattern: new URLPattern({ pathname: "/api/posts" }), handler: handlePosts.create },
  { method: "GET", pattern: new URLPattern({ pathname: "/api/posts/:id" }), handler: handlePosts.get },
  { method: "DELETE", pattern: new URLPattern({ pathname: "/api/posts/:id" }), handler: handlePosts.delete },
  { method: "POST", pattern: new URLPattern({ pathname: "/api/auth/login" }), handler: handleAuth.login },
  { method: "POST", pattern: new URLPattern({ pathname: "/api/auth/register" }), handler: handleAuth.register },
]

function matchRoute(req: Request): { handler: Handler; params: Record<string, string> } | null {
  const url = new URL(req.url)

  for (const route of routes) {
    if (route.method !== req.method) continue

    const match = route.pattern.exec(url)
    if (match) {
      return {
        handler: route.handler,
        params: (match.pathname.groups ?? {}) as Record<string, string>,
      }
    }
  }

  return null
}

function handleHealth(_req: Request): Response {
  return Response.json({
    ok: true,
    timestamp: new Date().toISOString(),
    memory: process.memoryUsage.rss(),
  })
}

const server: Server = Bun.serve({
  port: parseInt(process.env.PORT ?? "3000"),
  hostname: "0.0.0.0",

  async fetch(req) {
    const match = matchRoute(req)

    if (!match) {
      return Response.json({ message: "Not found" }, { status: 404 })
    }

    try {
      return await match.handler(req, match.params)
    } catch (err) {
      console.error("[Server error]", err)
      return Response.json({ message: "Internal server error" }, { status: 500 })
    }
  },

  // WebSocket support
  websocket: {
    open(ws) {
      console.log("[WS] connected", ws.remoteAddress)
    },
    message(ws, message) {
      ws.send(`echo: ${message}`)
    },
    close(ws) {
      console.log("[WS] disconnected")
    },
  },

  // TLS for production
  ...(process.env.NODE_ENV === "production" && process.env.TLS_KEY ? {
    tls: {
      key: Bun.file(process.env.TLS_KEY),
      cert: Bun.file(process.env.TLS_CERT!),
    },
  } : {}),
})

console.log(`🚀 Server running at ${server.url}`)

SQLite Database

// src/db/sqlite.ts — Bun SQLite with query helpers
import { Database } from "bun:sqlite"
import { existsSync } from "fs"

const DB_PATH = process.env.DATABASE_PATH ?? "./app.db"

const db = new Database(DB_PATH, { create: true })

// Enable WAL mode for concurrent reads
db.run("PRAGMA journal_mode = WAL")
db.run("PRAGMA synchronous = NORMAL")
db.run("PRAGMA cache_size = 10000")
db.run("PRAGMA foreign_keys = ON")

// ── Schema ─────────────────────────────────────────────────────────────────

function migrate() {
  db.transaction(() => {
    db.run(`
      CREATE TABLE IF NOT EXISTS users (
        id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
        email TEXT NOT NULL UNIQUE,
        name TEXT NOT NULL,
        hashed_password TEXT,
        role TEXT NOT NULL DEFAULT 'user',
        created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
      )
    `)

    db.run(`
      CREATE TABLE IF NOT EXISTS posts (
        id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
        title TEXT NOT NULL,
        slug TEXT NOT NULL UNIQUE,
        content TEXT NOT NULL,
        excerpt TEXT,
        published INTEGER NOT NULL DEFAULT 0,
        author_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
        updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
      )
    `)

    db.run("CREATE INDEX IF NOT EXISTS idx_posts_slug ON posts(slug)")
    db.run("CREATE INDEX IF NOT EXISTS idx_posts_author ON posts(author_id)")
  })()
}

migrate()

// ── Type helpers ───────────────────────────────────────────────────────────

type Post = {
  id: string
  title: string
  slug: string
  content: string
  excerpt: string | null
  published: number
  author_id: string
  created_at: string
}

// Prepared statements for hot paths
const getPostBySlug = db.prepare<Post, [string]>(
  "SELECT * FROM posts WHERE slug = ? AND published = 1",
)

const getPostById = db.prepare<Post, [string]>(
  "SELECT * FROM posts WHERE id = ?",
)

const listPosts = db.prepare<Post, [number, number]>(
  "SELECT * FROM posts WHERE published = 1 ORDER BY created_at DESC LIMIT ? OFFSET ?",
)

const insertPost = db.prepare<Post, [string, string, string, string | null, number, string]>(
  "INSERT INTO posts (title, slug, content, excerpt, published, author_id) VALUES (?, ?, ?, ?, ?, ?) RETURNING *",
)

export const postdb = {
  findBySlug: (slug: string) => getPostBySlug.get(slug),
  findById: (id: string) => getPostById.get(id),
  list: (limit = 10, offset = 0): Post[] => listPosts.all(limit, offset),
  create: (data: { title: string; slug: string; content: string; excerpt?: string; published: boolean; authorId: string }) => {
    return insertPost.get(data.title, data.slug, data.content, data.excerpt ?? null, data.published ? 1 : 0, data.authorId)
  },
}

export { db }

Bun Test Suite

// src/routes/posts.test.ts — Bun native test runner
import { describe, it, expect, beforeAll, afterAll, mock } from "bun:test"
import { Database } from "bun:sqlite"
import { handlePosts } from "./posts"

// In-memory test DB
const testDb = new Database(":memory:")

describe("Posts API", () => {
  beforeAll(() => {
    testDb.run(`CREATE TABLE posts (
      id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
      title TEXT NOT NULL,
      slug TEXT NOT NULL,
      content TEXT NOT NULL,
      excerpt TEXT,
      published INTEGER DEFAULT 0,
      author_id TEXT NOT NULL,
      created_at TEXT DEFAULT (datetime('now'))
    )`)
  })

  it("GET /api/posts returns empty list", async () => {
    const req = new Request("http://localhost/api/posts")
    const res = await handlePosts.list(req, {})

    expect(res.status).toBe(200)
    const body = await res.json() as { posts: unknown[] }
    expect(Array.isArray(body.posts)).toBe(true)
  })

  it("POST /api/posts creates a post", async () => {
    const req = new Request("http://localhost/api/posts", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        title: "Test Post Title",
        content: "x".repeat(20),
        published: true,
      }),
    })

    const res = await handlePosts.create(req, {})
    expect(res.status).toBe(201)
  })

  it("computes slug from title", () => {
    const slug = "Hello World! Special Chars #123"
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, "-")
      .replace(/^-|-$/g, "")
    expect(slug).toBe("hello-world-special-chars-123")
  })
})

Shell Scripting

// scripts/deploy.ts — Bun shell scripting
import { $ } from "bun"

const VERSION = process.env.VERSION ?? "latest"
const REGISTRY = process.env.REGISTRY ?? "registry.example.com"

async function deploy() {
  console.log("🔍 Running tests...")
  await $`bun test`.text()

  console.log("🏗️ Building...")
  const buildResult = await Bun.build({
    entrypoints: ["./src/index.ts"],
    outdir: "./dist",
    target: "bun",
    minify: true,
  })

  if (!buildResult.success) {
    for (const log of buildResult.logs) console.error(log)
    process.exit(1)
  }

  console.log(`📦 Building Docker image ${REGISTRY}/app:${VERSION}...`)
  await $`docker build -t ${REGISTRY}/app:${VERSION} .`

  console.log("🚀 Pushing...")
  await $`docker push ${REGISTRY}/app:${VERSION}`

  const deployTime = new Date().toISOString()
  await Bun.write("./dist/deploy.json", JSON.stringify({ version: VERSION, deployedAt: deployTime }))

  console.log(`✅ Deployed ${VERSION} at ${deployTime}`)
}

await deploy()

For the Node.js alternative when maximum ecosystem compatibility (native addons, mature npm packages with native bindings), larger deployment platform support, and an established production track record are paramount — Node.js has broader support for native modules while Bun is incompatible with some native addons but runs pure JS/TS packages well, see the Node.js guide. For the Deno alternative when built-in TypeScript, a permissions model for security sandboxing, native Web APIs (fetch, Temporal, etc.) without polyfills, and first-class JSR package registry support are preferred — Deno and Bun both target modern JS runtimes but Deno prioritizes security and standards while Bun prioritizes performance and Node.js compatibility, see the Deno guide. The Claude Skills 360 bundle includes Bun skill sets covering HTTP servers, SQLite, bundling, and testing. Start with the free tier to try Bun runtime development generation.

Keep Reading

Backend

Claude Code for Express.js Advanced: Patterns for Production APIs

Advanced Express.js patterns with Claude Code — typed request handlers with RequestHandler generics, async error handling middleware, Zod validation middleware factory, rate limiting with express-rate-limit and Redis store, helmet security middleware, compression, dependency injection with tsyringe, file upload with multer and S3, pagination utilities, JWT middleware, and structured logging with pino.

6 min read Jun 8, 2027
Backend

Claude Code for KeystoneJS: Node.js CMS and App Framework

Build full-stack apps with KeystoneJS and Claude Code — config with lists, fields.text and fields.relationship for schema definition, access control with isAuthenticated and isAdmin functions, hooks with beforeOperation and afterOperation, GraphQL API auto-generation from schema, AdminUI for content management, session with statelessSessions, Prisma adapter for database, file storage with images and files fields, and custom REST endpoints.

6 min read Jun 7, 2027
Backend

Claude Code for Hono Advanced: Edge-First Web Framework Patterns

Advanced Hono patterns with Claude Code — Hono RPC with hc typed client, factory createFactory for reusable middleware, validator middleware with Zod, streaming responses with streamText and streamSSE, WebSocket upgrader with upgradeWebSocket, Cloudflare Workers bindings with c.env, D1 database access, KV namespace, R2 bucket, middleware composition with compose, testing with app.request, and monorepo sharing of Hono RPC types.

6 min read Jun 6, 2027

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free