ADR-008: Monorepo and tooling stack
Date: 2025-01-10 (Phase 0) Status: Accepted Supersedes: — Superseded by: —
Context
ServerlessIRCd is a multi-package TypeScript project: a platform-agnostic
core (irc-core), an orchestration layer (irc-server), a reference runtime
(in-memory-runtime), two cloud adapters (cf-adapter, aws-adapter), and
several apps (local-cli, cf-worker, aws-stack). The toolchain must
support cross-package type checking, incremental builds, a unified test
runner, and CI that enforces coverage gates per package.
Decision
| Concern | Choice | Rationale |
|---|---|---|
| Package manager | pnpm (workspaces) | Fast, disk-efficient, first-class monorepo support |
| Build orchestration | turbo (caching) | Incremental builds, remote cache, task dependency graph |
| TypeScript | Project references + tsconfig.base.json |
Strict mode, exactOptionalPropertyTypes, noUncheckedIndexedAccess |
| Test runner | vitest | ESM-native, fast, integrates with Workers (vitest-pool-workers), built-in coverage |
| Coverage | v8 provider, gate ≥90% (100% on irc-core) |
Enforced in CI (.github/workflows/ci.yml) |
| Lint/format | Biome | Single tool (replaces ESLint + Prettier), fast, zero config drift |
| CF bundler | wrangler (esbuild internally) | Native Workers toolchain |
| AWS bundler | esbuild (Lambda bundles) + CDK v2 (infra) | Tree-shaking, fast cold starts |
| Runtime target | Node 20 (Lambda) + latest Workers runtime; ES2022+ | Aligns with platform-supported runtimes |
Consequences
Positive:
- pnpm workspaces + turbo give fast local dev: only changed packages rebuild; tests run incrementally.
- vitest's ESM-native design avoids the CJS/ESM interop pain that plagues
Jest-based monorepos. The same test files run under
vitest-pool-workers(realworkerd) for CF adapter tests. - Biome eliminates the ESLint/Prettier config drift problem — one tool, one
config, one command (
biome check). - TypeScript project references enforce package boundaries at compile time:
irc-corecannot accidentally import fromcf-adapter.
Negative:
- pnpm's strict node-linker can surprise contributors used to npm/yarn's
hoisting.
node_modulesis per-package; global scripts needpnpm --filter. - turbo's caching requires consistent environment hashing; a CI cache miss (e.g. different Node minor version) degrades to a full rebuild silently.
- Biome is newer than ESLint and lacks some ecosystem plugins. Custom rules
(e.g. "no ticket IDs in source files") are enforced via convention
(
AGENTS.md) rather than a Biome plugin.
References
- PLAN §9 — "Monorepo: pnpm + TypeScript project references; turbo for caching"
pnpm-workspace.yaml,turbo.json,tsconfig.base.json,biome.json.github/workflows/ci.yml— coverage gates and CI pipelineAGENTS.md— code style conventions