Software systems accumulate decisions that are obvious at the time and mysterious six months later. A database was chosen for a reason, a synchronous call became asynchronous for a reason, and a service boundary exists because some trade-off mattered.

Architecture Decision Records, or ADRs, preserve that reasoning in small documents close to the code.

Record decisions, not meetings

An ADR should answer a future engineer’s practical questions:

  • What problem were we solving?
  • What constraints mattered?
  • What did we decide?
  • Which alternatives were considered?
  • What consequences did we accept?
  • Has this decision been replaced?

It does not need to reproduce a design meeting transcript.

A concise record is more likely to stay readable.

Use a small stable template

A lightweight structure is enough:

# ADR-0042: Use asynchronous events for audit fan-out

Status: Accepted
Date: 2026-09-02

## Context
What forces and constraints require a decision?

## Decision
What are we choosing?

## Consequences
What becomes easier, harder, or newly required?

## Alternatives considered
What credible options did we reject and why?

Teams can add owners, links, or review dates, but the template should not become a form with dozens of fields.

Write context before the solution

Weak ADRs begin with a preferred technology and then justify it.

Strong ADRs describe the problem in terms that remain useful even if the chosen technology changes:

The checkout API currently writes an audit record synchronously.
The audit store has a separate availability profile, and failures there
cause otherwise-valid purchases to fail. Audit delivery may be delayed
for up to five minutes, but records must not be silently lost.

That context explains the reliability constraint without presupposing a message broker.

Make the decision concrete

Avoid vague statements such as:

We will improve resilience with event-driven architecture.

Prefer a specific decision:

After the purchase transaction commits, the service will publish an
audit event to the existing durable queue. A separate consumer will
write the audit record. The purchase response will not wait for the
audit database.

A decision should be specific enough that an implementation can be reviewed against it.

Consequences are part of the decision

Every architecture choice buys something and costs something.

For the asynchronous audit example, consequences might include:

  • checkout no longer depends on audit-database latency;
  • audit data becomes eventually consistent;
  • the event publisher needs an outbox or equivalent delivery guarantee;
  • consumers must handle duplicate delivery safely;
  • operational monitoring must include queue lag.

Writing consequences prevents a document from sounding like a technology endorsement.

Include credible alternatives

Alternatives show the decision boundary.

Useful alternatives might be:

  • keep synchronous writes but add a timeout;
  • write audit data in the checkout database;
  • use a periodic batch export;
  • publish to the existing event platform.

Do not invent weak alternatives merely to make the selected option look good.

If only one option was genuinely possible because of a hard constraint, document that constraint.

Keep accepted ADRs historically stable

Once accepted, an ADR is a historical record. Editing its reasoning months later can erase what the team actually knew at the time.

Small corrections are fine, but a meaningful change should usually create a new ADR that supersedes the old one.

For example:

Status: Superseded by ADR-0061

This preserves the evolution of the system.

Store ADRs near the codebase

A common location is:

docs/adr/
  0001-use-postgresql.md
  0002-separate-worker-process.md
  0003-adopt-api-versioning.md

Keeping ADRs in version control gives them code review, history, searchability, and the same access model as the implementation.

Another documentation system can work if engineers actually use it. The important property is discoverability from the system being changed.

An ADR should not become an isolated essay.

Useful links include:

  • the issue that triggered the decision;
  • relevant diagrams;
  • migration plans;
  • pull requests;
  • operational runbooks.

Links can age, so the ADR itself should still contain enough reasoning to stand alone.

Know what deserves an ADR

Record decisions that are expensive, cross-cutting, difficult to reverse, or likely to surprise future maintainers.

Examples include:

  • choosing a storage model;
  • defining service boundaries;
  • adopting an API compatibility policy;
  • deciding on consistency guarantees;
  • standardizing deployment topology;
  • selecting a long-lived framework.

Do not create an ADR for every function name or routine refactor.

Review ADRs during relevant changes

The best time to read ADRs is when code approaches the boundary they describe.

Code review templates or subsystem READMEs can link to important decisions. A developer changing an authentication flow should be able to discover the ADRs that explain its trust boundaries.

An ADR library that no one consults is only archival documentation.

Common mistakes

Writing after the decision has become folklore

Capture the record while constraints and rejected alternatives are still fresh.

Recording only benefits

Trade-offs are the information future maintainers need most.

Treating an ADR as permanent law

Decisions can be superseded. Preserve history instead of freezing architecture.

Creating huge templates

Documentation that is expensive to write will be skipped when decisions move quickly.

Mixing several unrelated decisions

One ADR should have one coherent decision. Split independent choices so they can evolve separately.

A useful definition of done

An accepted ADR should let a future engineer explain:

  1. the problem and constraints;
  2. the selected approach;
  3. the main alternatives;
  4. the accepted costs;
  5. how to tell whether the decision has been superseded.

That is enough to turn architectural memory from oral tradition into versioned engineering context.