Skip to content

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 to Superseded 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 .sln and 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 ADRIntent: 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 sweepIntent: review accepted ADRs each quarter; flip stale ones to Deprecated. Prevents the log from rotting silently.
  • Onboarding curriculumIntent: 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 retrospectivesIntent: 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: Negative bullet 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 Superseded or Withdrawn.
  • ⚠️ 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