ADR-0003: Biome for lint + format
ADR-0003: Biome for lint + format
Section titled “ADR-0003: Biome for lint + format”Status: Accepted Date: 2026-04-20
Context
Section titled “Context”Every TypeScript project needs a linter and a formatter. Two families of tooling exist: the traditional combination (ESLint + Prettier, two tools, two configs, mature ecosystem) and the newer unified tools (Biome, dprint). The tooling running on developer machines and in CI should be fast, consistent, and low-friction.
Decision
Section titled “Decision”Use Biome 2 for both linting and formatting. Single tool, single config (biome.json), single invocation. No ESLint, no Prettier.
Consequences
Section titled “Consequences”- One config, one version to track, one cache to invalidate. Less yak-shaving.
- Biome is ~10–100× faster than ESLint + Prettier on equivalent rulesets. Matters less at our size today; matters a lot by the time we have 100+ files.
- Biome’s import-sort runs as part of
lint:fix. No separate organize-imports step. - Plugin ecosystem is smaller than ESLint’s. If we ever need a custom AST rule or an ESLint-only plugin (e.g., for a specific framework we don’t yet use), we’ll reconsider — adopting ESLint alongside is an option at that point, not a disaster.
- Markdown and many other file types aren’t formatted by Biome 2. Acceptable; editorconfig handles whitespace for non-source files.
- Biome 2.x is still pre-LTS. Upgrades may have rule-set changes. Mitigated by pinning the version in
biome.json’s$schemaandpackage.json.
Alternatives considered
Section titled “Alternatives considered”- ESLint + Prettier: largest ecosystem, most documentation. Slower, two configs, two failure modes for “why is my code being reformatted.” Default choice if we need a rule Biome doesn’t have.
- dprint: similar philosophy to Biome, smaller community, plugin-per-language model. Biome’s integrated linting tips the balance.
- Oxc: very fast, Rust-based, still maturing. Worth re-evaluating in a year.
- No linter, just formatter: rejected — linting catches real bugs (
noUnusedVariables,useImportType) that typecheck doesn’t.