Steven's Knowledge

Architecture Decision Records

A lightweight format for capturing significant decisions — what was chosen, what was considered, and why

Architecture Decision Records

Every project accumulates decisions that are not visible in the code: which library was chosen over which alternatives, why the bounded contexts were split this way, why a constraint that looks arbitrary is in fact load-bearing. Six months later, no one remembers. The decision is reopened, re-debated, sometimes silently reversed — and the cost paid the first time is paid again.

An Architecture Decision Record (ADR) is a small text file that captures one decision: what was chosen, what was rejected, and the reasoning that connected them. The format is deliberately humble. Written well, ADRs survive turnover, onboarding, and the slow drift of intent.

What an ADR Is For

A useful ADR delivers three things:

  1. The decision itself, in a form precise enough that it can be executed.
  2. The alternatives considered, so the reader can reconstruct why this one won.
  3. The forces in tension, so future engineers can recognize when those forces have shifted and the decision should be revisited.

What an ADR is not:

  • A design document. Designs are larger; ADRs record a single decision within or about a design.
  • A meeting minutes. Discussion belongs in the meeting; the resolution belongs in the ADR.
  • A blog post. The audience is engineers who will inherit this decision, not the public.
  • A permanent commandment. Decisions get superseded; ADRs accommodate that.

When to Write One

Not every decision needs an ADR. The threshold is roughly:

Write an ADR when the decision is hard to reverse, has more than one reasonable answer, and will affect engineers who were not in the room.

Examples that meet the bar:

  • Choosing a database, message broker, or runtime.
  • Adopting (or rejecting) a state management library, an ORM, a build tool.
  • Drawing the boundary between two services or modules.
  • Adopting a coding convention that overrides team default style.
  • Choosing an authentication / authorization model.
  • Picking a deployment topology, region strategy, or scaling model.
  • Declining to do something the team keeps proposing — recorded so the discussion stops resurfacing.

Examples that do not:

  • Variable names.
  • Internal helper functions.
  • One-off bug fixes.
  • Anything reversible in an afternoon.

The bar moves down for early-stage projects (almost every decision is consequential) and up for mature ones (most decisions are local).

The Format

The format made famous by Michael Nygard is short on purpose:

# ADR-NNNN: Title

## Status
Proposed | Accepted | Deprecated | Superseded by ADR-XXXX

## Context
What is the situation? What forces are at play?

## Decision
What did we decide?

## Consequences
What follows from this decision — good, bad, and trade-off?

That is the whole template. Five sections, a few paragraphs each. Resist the urge to grow it.

Title

A noun phrase, not a question. "Use PostgreSQL for primary storage," not "What database should we use?" The title is what shows up in the index; it should state the decision.

Status

A controlled vocabulary:

  • Proposed — under discussion.
  • Accepted — in effect.
  • Deprecated — no longer in effect, no replacement.
  • Superseded by ADR-NNNN — replaced by a later decision.

ADRs are not deleted when overturned. They are marked superseded and left in place. The chain of decisions is part of the record.

Context

What was true when the decision was made. Constraints, requirements, observed pain points, prior decisions that bound the space. Two failure modes:

  • Too little context. A reader two years later cannot tell what problem this was solving.
  • Too much context. Every meeting note and Slack thread pasted in. The signal drowns.

A useful test: if the relevant constraints changed, would a reader recognize it from this context section? If not, the section is incomplete.

Decision

A direct statement. "We will use PostgreSQL." Not "We may consider PostgreSQL." Hedging belongs in Context (the forces) or Consequences (the trade-offs), not in the decision itself.

If the decision has parts, enumerate them:

## Decision
1. Primary storage will be PostgreSQL 15.
2. Read replicas will be added in regions A and B before the next release.
3. Migrations will be managed with <tool>.

Consequences

The honest part. What does choosing this cost? What does it foreclose? What follow-on work does it imply?

Three categories help:

  • Positive. What this decision buys.
  • Negative. What it costs.
  • Neutral / follow-up. What it implies but does not by itself solve.

The negative section is the one most often skipped and the one most worth writing. A decision with no listed downsides has not been examined critically.

Alternatives (optional but often valuable)

Many teams add an "Alternatives Considered" section. It is worth the space:

## Alternatives Considered

### MySQL
Pros: team familiarity, mature operational tooling.
Cons: JSON support less mature than Postgres; weaker support for the
geospatial features the location module will need.
Why rejected: the geospatial requirement is on the near-term roadmap.

### MongoDB
Pros: schema flexibility.
Cons: the data is fundamentally relational; we would re-invent JOINs
in application code.
Why rejected: shape of data is wrong for the store.

The point is not to be exhaustive. The point is to record what was seriously considered, so the next person to ask "have we considered X?" can read the answer instead of starting the conversation over.

Where ADRs Live

Two options work; pick one:

In the repository

A docs/adr/ directory at the root, with files named 0001-title-in-kebab-case.md. Version-controlled with the code; updated by the same PR that makes the change.

This is the default. The ADR moves with the code it describes; reviewers see it in the same PR as the implementation; the history is preserved by git.

In a wiki or knowledge base

Acceptable when decisions span multiple repositories or live above the code level. Risks: ADRs and code drift apart; ownership is unclear; permissions get awkward.

For a single-repository or single-team decision, prefer the repository.

Writing the Decision

A useful drafting sequence:

  1. State the decision in one sentence. If you cannot, you do not have one decision — you have several. Split.
  2. List the alternatives. Three is usually the right number: the chosen one and two losers. One alternative ("we will not do nothing") is too few; ten is unread.
  3. For each alternative, state the strongest argument for it. Steelmanning the rejected options is the test that the decision was made on merits.
  4. Write the consequences. Force yourself to write at least one negative consequence. If there genuinely are none, the decision did not have stakes.
  5. Circulate before accepting. Status "Proposed." Get pushback. Move to "Accepted" only after the team has had a chance to disagree.

A draft that survives this sequence is one a future engineer can trust.

Updating and Superseding

Decisions get overturned. The discipline is to record the overturning, not erase the original.

# ADR-0007: Use PostgreSQL for primary storage

## Status
Superseded by ADR-0042 (2024-03-15)

## Context
...

And in the new ADR:

# ADR-0042: Migrate primary storage to CockroachDB

## Status
Accepted

## Context
ADR-0007 chose PostgreSQL. Two years later, multi-region write
latency has become the binding constraint. ...

The pair tells the full story: what was true, what changed, what was done.

What Goes Wrong

A few patterns:

  • Decision theater. ADRs written after the fact to ratify a decision already executed. The exercise produces a document but does not capture the reasoning, because the reasoning is reconstructed.
  • The 200-page ADR. A decision that needs 200 pages to justify is a design document, not an ADR. Write the design, link to it, keep the ADR short.
  • Status never updated. Decisions marked Proposed two years ago. Either accept them, decline them, or delete them.
  • No one reads them. ADRs that exist but are not referenced in code reviews, design discussions, or onboarding. Either the team does not need them, or the practice has not taken root — both are problems worth diagnosing.
  • Decisions disguised as discussion. "We will probably want to revisit this; for now, let's lean toward X." That is not a decision; it is a pause. ADRs are for the moments work depends on the answer.

What Goes Right

A team using ADRs well looks like:

  • New engineers can read the ADR index and understand the load-bearing decisions in a day.
  • Code reviewers point at ADRs to explain why a change does or does not fit.
  • Disagreements are settled by writing the alternatives and consequences down, not by re-arguing.
  • Old decisions get reopened with new ADRs, not silent reversals.
  • The index of decisions becomes a map of the system's intent.

That last item is the one that compounds. The codebase shows what the system does; the ADRs show why it does it that way and not another. Both are needed to maintain it.

Pre-Commit Question

Before merging an ADR, ask:

Could someone who was not in the discussion reconstruct the decision from this document alone?

If yes, the ADR has done its job. If no, the gap is what to write next.

On this page