ADRs at Scale
Key Points
- ADRs (Architecture Decision Records) capture the why — the single artifact that survives team turnover.
- In-repo, numbered, immutable. Edit only Status; never rewrite a decided record.
- Supersede, don't delete. New ADR with
Supersedes ADR-N; old one updated toSuperseded by ADR-M. - An ADR records a decision; an RFC proposes one. RFCs become ADRs once the team agrees.
- Onboarding gold. A new joiner reading 30 ADRs in a day understands more than reading 30k LOC.
- Templates are fungible — Nygard, Y-Statements, MADR all work. Pick one and stick to it.
- The shortest viable ADR beats the perfect one nobody writes.
Concepts (deep dive)
What an ADR is (and isn't)
A short, immutable record of an architectural decision and the reasoning behind it. One decision per ADR. Lives next to the code that implements it.
It is not: - A spec (specs change; decisions don't, they get superseded). - A design doc (design docs are forward-looking; ADRs are decisional). - A wiki page (wikis drift; ADRs are reviewed via PR).
Why they earn their keep at senior+ level
- Future-self alignment. "Why did we pick Postgres over Cosmos?" answered in 60 seconds.
- Prevents re-litigation. The fourth time someone asks "should we use MongoDB?" you link ADR-12.
- Onboarding accelerator. The honest answer to "how does this codebase work" lives in the ADR log, not the README.
- Decision discipline. Writing the ADR forces honest comparison; the act of writing surfaces unstated assumptions.
- Audit / compliance. SOC2 and similar reviews love a dated, signed-off decision trail.
Templates worth knowing
Michael Nygard (the original, 2011)
# ADR-NN: Title
## Status
Proposed | Accepted | Deprecated | Superseded by ADR-MM
## Context
The forces in play. Constraints. What's true today.
## Decision
The change being made. Active voice: "We will…"
## Consequences
What becomes easier. What becomes harder. What we accept.
Four sections, ~1 page. Has aged better than most templates.
Y-Statements (Olaf Zimmermann)
A single sentence:
In the context of
<use case>, facing<concern>, we decided for<option>and neglected<alternatives>, to achieve<quality>, accepting<downside>.
Forces brevity. Pairs well with Nygard for tiny decisions.
MADR (Markdown Architectural Decision Records)
Structured Markdown with frontmatter, decision drivers, considered options, pros/cons per option, and links. Heavier; better when ADRs are exported into a published catalog.
Anatomy that matters most
- Status field is the only mutable part. Lifecycle:
Proposed → Accepted → Deprecated | Superseded. - Context section must read standalone in 5 years. Don't say "the new service" — name it.
- Decision in present tense. "We use X" — sounds odd when reading old ADRs but reads correctly at decision time.
- Consequences include the negative. All-pros ADRs are red flags.
Where to put them
- In the repo:
docs/adr/0001-record-architecture-decisions.md, sequentially numbered. - Numbered, zero-padded.
0001,0002— easy sort, easy linking. - Immutable filenames. Don't rename the title; create a new ADR if the topic genuinely changed.
- Reviewed via PR, like code. Approval = team consensus; merge = "Accepted".
For organizations with cross-repo decisions (org-wide standards), maintain a separate architecture-decisions repo and link from product repos.
The Fishbowl supersession pattern
When ADR-23 supersedes ADR-7: - ADR-23 status: Accepted. First line of context: Supersedes ADR-7. - ADR-7 status: Superseded by ADR-23. Body unchanged. - Both stay in the log, linked. The history is the value.
The temptation is to delete or rewrite ADR-7 "because it's wrong now". Resist — the wrong answer at the time is itself important context.
Indexing & tooling
- adr-tools — bash CLI:
adr new "Use Postgres",adr status superseded N. Zero ceremony. - log4brains — generates a static site from your ADR folder; great for cross-team browsability.
- GitHub Pages or DocFX publishing of
docs/adr/for non-engineering stakeholders. - PR template hooks — checkbox: "Does this PR need an ADR? If yes, link it." Catches the missing ones.
ADRs vs RFCs — the lifecycle
| Stage | Artifact | Status |
|---|---|---|
| Idea / proposal | RFC (Request For Comment) | Draft, In Review |
| Decision made | ADR | Accepted |
| Decision reversed | New ADR | Supersedes prior |
Some teams fold RFCs into ADRs with status Proposed; others keep them separate (RFCs in docs/rfc/, ADRs in docs/adr/). Both work — pick one.
Dotnet shop specifics
- Store in
docs/adr/at solution root. The.slnand the ADRs travel together. - Reference ADRs in code comments:
// See ADR-0014 for why this is sync, not async. - Generate ADR scaffolds from your PR template: a checkbox creates a stub
docs/adr/NNNN-<branch>.md. - For multi-repo monoliths, mirror the index into a central engineering wiki — but the source of truth stays in-repo.
- Consider including ADR diffs in code-review checklists for architecturally significant PRs.
Patterns
- The 5-line ADR — Intent: for small decisions, write a Y-Statement only. Lower the activation energy; more decisions get captured.
- ADR per pull request (when warranted) — Intent: PR introducing a new pattern includes the ADR that justifies it. Decision and code travel as one unit.
- Quarterly ADR sweep — Intent: review accepted ADRs each quarter; flip stale ones to
Deprecated. Prevents the log from rotting silently. - Onboarding curriculum — Intent: new joiners read the ADR log on day 1-2, write a "questions about ADRs" doc by end of week 1. Forces real engagement.
- ADR-driven retrospectives — Intent: when something blew up, ask "which ADR was wrong, and what supersedes it?" Connects postmortems back to architecture.
Pros & cons / trade-offs
| Aspect | Pros | Cons |
|---|---|---|
| In-repo storage | Versioned, PR-reviewed, travels with code | Less discoverable for non-eng |
| Wiki / Confluence storage | Discoverable, links to other docs | Drifts from code, weak history |
| Heavy template (MADR) | Comprehensive, auditable | Higher write cost, fewer ADRs written |
| Light template (Nygard) | Fast to write, lower friction | Less structured for catalogs |
| Numbered & immutable | Stable links, audit-friendly | Renumbering costs (avoid) |
| Free-form titles | Expressive | Harder to search/index |
When to use / when to avoid
✅ Write an ADR when: choosing tech stack, framework, pattern, library; making a backward-incompatible change; deviating from a previous ADR; adopting an org-wide standard; making a decision someone could reasonably re-question in 6 months.
❌ Don't write an ADR for: variable naming, function signatures, library version bumps within the same major, cosmetic refactors, sprint-scoped product decisions (those are tickets, not architecture).
Senior-level tips
- 💡 First ADR in any repo: ADR-0001 "Record architecture decisions" — it's self-justifying and seeds the practice.
- 💡 Co-author ADRs with juniors to teach decision-making. The doc is the artifact; the conversation is the lesson.
- 💡 An ADR with no
Consequences: Negativebullet is incomplete — every decision has a downside; surface it. - 💡 Date the ADR. Filename has the number, but the merge date is what tells you "we knew that in Q2 2024".
- 💡 Link liberally to PRs and tickets that motivated the decision. Backlinks are search gold.
- 💡 When superseding, write why the old one was wrong in the new ADR — facts changed, scale changed, technology matured. Naming the reason prevents repeating the cycle.
- 💡 Don't write retroactive ADRs in a vacuum. "ADR for the way the code already works" is fine if you actually treat it as a decision review, not just documentation.
- 💡 Reference ADRs in code review. "This contradicts ADR-9 — should we update the ADR or the PR?" beats arguing from taste.
Common pitfalls
- ⚠️ Wish-list ADRs — "we should adopt X" with no decision authority.
- ⚠️ Editing accepted ADRs in place. The historical record is the value; preserve it.
- ⚠️ ADRs that are 12 pages long. If it's that big, it's an RFC or a design doc.
- ⚠️ Numbering gaps from deleted ADRs. Don't delete; mark
SupersededorWithdrawn. - ⚠️ Pre-decided ADRs that pretend to compare options. Reviewers see through it; trust erodes.
- ⚠️ ADR log that nobody reads. Onboard, link from PRs, mention in standups — make it part of the team's working memory.
- ⚠️ Writing ADRs only for decisions that "feel important". The unsexy ones (logging library, error handling convention) save the most future debate.
- ⚠️ Mixing ADR template styles within one log. Pick Nygard or MADR — consistency aids reading.
Further reading
- Michael Nygard — Documenting Architecture Decisions (the original)
- ThoughtWorks Tech Radar — Lightweight Architecture Decision Records (Adopt)
- Olaf Zimmermann — Y-Statements
- MADR — Markdown Any Decision Records
- adr.github.io — community catalog of templates
- Joel Parker Henderson — architecture-decision-record (templates and examples)
- AWS — Architecture Decision Records guide
- Spotify Engineering — When should I write an ADR? (search "ADR")
- log4brains — ADR site generator