Architecture Decision Records

Every codebase contains decisions whose reasoning has evaporated. Why is there a queue between these two services when a direct call would work? Why does this module use a completely different validation library from everything else? Why was the obvious approach rejected? The code shows what was decided. Git history shows when. Neither shows why, or what alternatives were considered and found wanting.

An architecture decision record is a short document capturing one significant decision, its context, and its consequences. The format is deliberately minimal — a page, in Markdown, in the repository, immutable once accepted. The point isn't documentation for its own sake; it's that six months later someone will propose the thing you already rejected, and either you'll spend an hour re-deriving the reasoning or you'll link to the ADR.

The most valuable field is the one people skip: the options you considered and didn't take. That's the part that's genuinely unrecoverable from any other source.

TL;DR

Quick Example

That's the whole thing. The reason it works is the middle two sections: someone proposing "let's just use a database per tenant" in a year gets an answer with numbers attached, and someone debugging a latency regression knows RLS was a known 3–8% cost rather than a surprise.

Core Concepts

The template

Variants exist — MADR adds decision drivers and a pros/cons list per option; Nygard's original is the four-section form above. Pick one and use it consistently; the format matters far less than the habit.

Immutability and supersession

An accepted ADR is a historical record of what was decided and why at that time. Editing it destroys the record — and the record is the entire value. When the decision changes, write a new ADR, mark the old one superseded, and link both directions.

This also means an ADR being "wrong" in hindsight is not a problem. It documents a decision made with the information available, which is exactly what a future reader needs to understand why the system looks the way it does.

What deserves an ADR

Two useful tests. The reversal test: if changing your mind later would take more than a week, write it down. The argument test: if two competent engineers could reasonably disagree, the reasoning is worth recording.

That last row in the "write one" column deserves emphasis — an ADR explaining why you didn't use the obvious technology is often the most valuable one in the directory, because it's the decision people will keep re-proposing.

Where they live

Sequential zero-padded numbers, never reused. In the repository so they're reviewed in a PR, versioned with the code, and findable by grep. Tooling like adr-tools or log4brains handles numbering and index generation, though a template file and a convention work fine.

For a monorepo or a multi-service organization: service-specific ADRs in the service's directory, cross-cutting ones in a central location. Duplicating cross-cutting decisions per service guarantees divergence.

The review process

ADRs go through pull request review like code, and the review is where most of their value is created — the discussion surfaces alternatives nobody had considered and forces the "why not X?" question to be answered explicitly.

Set a decision deadline. An ADR that sits in "Proposed" for three weeks is blocking work, and the discussion has usually converged long before the last comment.

Best Practices

Write it before or during the decision, not after

An ADR written while the decision is live captures genuine uncertainty and real alternatives. One written afterward is a rationalization — you already know the answer, so the alternatives get a paragraph of dismissal each. The document is much less useful, and writing it feels like a chore because it is one.

Be specific about consequences, especially the bad ones

"3–8% latency increase on our five heaviest endpoints" is useful. "Some performance impact" is not. And an ADR listing only benefits tells a future reader nothing about what to watch for — the negative consequences are the ones they'll encounter.

Include the alternatives you rejected, with reasons

This is the section that saves the most time later, because it's the one that answers "why didn't they just…?" A rejected option with a one-line reason ("too slow" ) is nearly as useless as no section at all — say what was measured or what constraint it violated.

Keep it to one page

An ADR is a decision record, not a design document. If it's running to five pages, either it's several decisions (split it) or it's a design doc with a decision buried in it (write the design doc separately and link it).

Link them from the code

A comment pointing at the ADR is how a reader encountering the surprising code finds the reasoning. Without it, the ADR directory is a place people look only if they already suspect it exists.

Generate and maintain an index

A README listing every ADR with its title, status, and date makes the set browsable. Automate it — a manually maintained index goes stale in a month, which is ironic and avoidable.

Don't retrofit everything

Backfilling five years of decisions is a large project with low returns, and the reconstructed reasoning is unreliable anyway. Write ADRs going forward, and backfill only the decisions that are actively being questioned — those are the ones where the record has value.

Common Mistakes

Editing an accepted ADR

No alternatives section

Consequences that are all upside

A design document wearing an ADR's clothes

ADRs for everything

Writing them and never referencing them

FAQ

How is an ADR different from a design document?

Scope and lifetime. A design doc describes how something will be built — schemas, interfaces, sequence diagrams, a rollout plan — and becomes obsolete once built. An ADR records why one option was chosen over others and stays relevant for the life of the system. A large project often has one design doc and several ADRs, and the design doc should link to them.

How is it different from an RFC?

Mostly process. An RFC is a proposal circulated for comment before a decision, often with a broader audience and a comment period. An ADR is the record of a decision, which may or may not have gone through an RFC first. Many organizations use both: RFC to reach the decision, ADR to record it. Some use one document for both by starting it in "Proposed" status.

Who writes them?

Whoever is making or driving the decision — usually a tech lead, a staff engineer, or the person doing the work. Not a designated documentarian, who wasn't in the discussion and can only transcribe conclusions. The review is where the team participates.

What if the decision turns out to be wrong?

That's a normal and expected outcome, and the ADR is still valuable: it explains why the system looks the way it does and what information was available at the time. Write a new ADR superseding it, and include in the context what you learned. An ADR trail showing a decision, its failure, and the replacement is more useful than either document alone.

How many should we have?

Far fewer than feels natural. A mature codebase might have 20–50 accumulated over years — a handful per quarter. If you're writing several a week, the threshold is too low and the directory will stop being read. If you've written none in a year on an actively evolving system, decisions are being made without a record.

We have five years of undocumented decisions. Where do we start?

Don't try to backfill. Start writing ADRs for decisions as they come up, and add a small number of retroactive ones for the decisions people keep asking about — usually three to five. Those are where the value is concentrated, and reconstructing the rest produces documents that are plausible rather than accurate.

Related Topics

References