ADR-001: Bun as the Application Runtime
Status: Accepted
Context
A modern full-stack TypeScript project needs a runtime, package manager, bundler, and test runner. Historically these were separate tools: Node.js (runtime) + npm/yarn/pnpm (packages) + webpack/Vite (bundler) + Jest/Vitest (tests). Each tool adds configuration overhead, version-pinning friction, and its own cold-start cost.
The key requirements were:
- Native TypeScript execution without a compile step in development
- Fast package installs and a single lockfile
- A built-in bundler that can produce a production frontend bundle
- A test runner that runs in the same runtime as the application code
- Automatic
.envloading withoutdotenv - Low overhead for a boilerplate that others will clone and customise
Decision
Use Bun as the sole runtime, package manager, bundler, and test runner across the entire stack — both backend and frontend.
| Concern | Tool | Replaces |
|---|---|---|
| Runtime | Bun.serve() | Node.js + Express/Fastify |
| Package manager | bun install | npm / yarn / pnpm |
| Bundler | Bun bundler | Vite / webpack / esbuild |
| Test runner | bun:test | Jest / Vitest |
| Env loading | Bun.env (built-in) | dotenv |
| File I/O | Bun.file() | fs.readFile / fs.writeFile |
| Shell commands | Bun.$\cmd“ | execa / child_process |
Specific Bun capabilities used in this codebase:
Bun.serve()— the HTTP + WebSocket server; routes are declared as a plain object, no framework overheadBun.password.hash()/Bun.password.verify()— native argon2 / bcrypt, no native addon compilation- HMR in dev —
import.meta.hotfor frontend hot module reloading without Vite --hotflag —bun --hot backend/server.tsfor backend hot reload in developmentbun:testwithhappy-dom— frontend and backend unit tests in a singlebun testcommand
Consequences
Positive
- Single toolchain:
bun install,bun dev,bun test,bun run build— no config files for each tool - 3× faster installs than npm; lockfile is a single
bun.lock - TypeScript runs natively — no
tscstep in development or tests - Native password hashing via
Bun.password— nobcryptnative addon .envfiles loaded automatically —dotenvremoved from dependencies
Negative / Risks
- Bun is newer than Node.js; some npm packages assume Node.js internals and may have edge-case incompatibilities
- The Bun bundler has fewer plugins than webpack/Vite; complex bundling scenarios may need workarounds
- Team members unfamiliar with Bun need a short orientation; Node-specific mental models (e.g.
process.envvsBun.env) apply but Bun adds its own APIs - Rate-limiting middleware is in-memory (single instance); a Redis-backed alternative is needed for multi-process deployments (documented in the rate limiter source)