Architecture Decisions
How we make, document, and communicate significant architectural choices using ADRs and design docs.
Overview
An architecture decision is any choice that shapes the structure of a system in a way that is hard to reverse: a new dependency, a data model, a service boundary, a protocol, a caching strategy. These decisions happen constantly — in Slack threads, in pull requests, in hallway conversations. The problem is not that the decisions are made; it is that they are made invisibly, and the reasoning behind them disappears almost immediately.
Architecture Decision Records (ADRs) are a lightweight mechanism for capturing what was decided, why, and what trade-offs were accepted. They are not bureaucracy. They are team memory — persistent, searchable, and attached to the codebase where the decision lives.
For the process of reviewing designs before a decision is finalized, see Design Review Frameworks.
Why It Matters
Context rots fast. The engineer who made a decision understands the constraints that drove it: the performance requirements at the time, the library that didn't exist yet, the operational trade-off that seemed acceptable. Six months later, that context is gone. New engineers encounter the outcome of the decision with none of its rationale, assume it is either wrong or legacy, and either work around it or spend a sprint relitigating a settled question.
Undocumented decisions get reversed accidentally. If nobody knows that a choice was deliberate, the next engineer to touch that code will undo it — and reintroduce the problem it was solving. An ADR makes the decision legible. "We tried that approach; here's why it doesn't work" is one of the most valuable sentences in an engineering organization.
The act of writing clarifies the decision. A decision you cannot articulate in writing is probably not a decision yet — it is an assumption. Drafting an ADR forces the author to name the alternatives that were considered and explain why they were rejected. This exercise regularly surfaces unconsidered angles before any code is written.
Onboarding time compresses. A new engineer who can read the decision log for a service understands months of context in hours. Without it, that context must be extracted through interviews, code archaeology, and trial and error. ADRs are one of the highest-leverage investments in onboarding quality.
Standards & Best Practices
What triggers an ADR
Not every decision needs one. The threshold is: would a future engineer reasonably question this decision, or waste time trying to change it without knowing why it exists? Decisions that typically warrant an ADR:
- Adopting a new external dependency or replacing an existing one
- Introducing a new service, queue, or data store
- Defining a cross-team API or event contract
- Choosing between architectural patterns (e.g. REST vs. GraphQL, event-driven vs. request-response)
- Accepting a known performance or security trade-off
- Deprecating or replacing an existing system component
Decisions that do not need an ADR: implementation choices within an established pattern, library version bumps, internal refactoring with no external interface change.
ADR format
Keep ADRs short and structured. The standard format has five sections:
Title — A short imperative phrase: "Use PostgreSQL as the primary data store", not "Database decision".
Status — Proposed, Accepted, Deprecated, or Superseded by ADR-042.
Context — The situation that forced a decision. What constraints existed? What problem were we solving? What alternatives were on the table? This is the section that future readers need most; do not shortchange it.
Decision — What we chose, stated plainly. One or two sentences.
Consequences — What becomes easier, what becomes harder, what we are accepting as a known downside. A consequences section with only positives is a red flag — every architectural decision involves trade-offs.
Keep ADRs in the repository
ADRs live in docs/decisions/ in the relevant repository. They are committed to version control like code. They are not in a wiki, a Notion doc, or a Confluence page — those are disconnected from the codebase and are routinely lost when teams migrate tools.
File naming: ADR-NNN-short-title.md, numbered sequentially. Never reuse a number; never delete an ADR. If a decision is reversed, update its status to Superseded by ADR-NNN and write the new ADR.
Link ADRs from pull requests
When a PR implements an architectural decision, reference the ADR in the PR description. When a PR creates a new ADR, it should be reviewed before the implementation PR opens — the design precedes the build.
When a full design doc is needed instead
An ADR captures a single decision point. Some changes are too large for an ADR — they involve multiple interacting decisions, require input from several teams, or carry enough risk that a structured review is warranted. For those, write a design doc instead.
The bar for a design doc: the change will take more than one sprint to implement, touches a cross-team interface, or introduces a new system component. For everything else, an ADR is sufficient.
How to Implement
Starting an ADR
- Create
docs/decisions/in the repository root if it does not already exist. - Copy the ADR template (see below). Set status to
Proposed. - Fill in Context first — articulate the problem before writing the decision.
- List the alternatives you considered and why each was rejected.
- Write the Decision and Consequences sections.
- Open a PR. The ADR should be reviewed and merged before implementation begins.
- Update status to
Acceptedwhen merged.
ADR status lifecycle
| Status | Meaning |
|---|---|
Proposed | Under discussion — not yet accepted |
Accepted | Decision is in effect |
Deprecated | Decision is no longer recommended but the system still reflects it |
Superseded | A newer ADR replaces this one — link to the replacement |
Communicating decisions
When an ADR is accepted, post a brief summary in the relevant engineering channel. One paragraph: what was decided, a link to the ADR, and any action required from other engineers. Don't assume people read merged PRs.
Tools & Templates
ADR template
# ADR-NNN: [Short imperative title]
**Status:** Proposed
**Date:** YYYY-MM-DD
**Authors:** [Name(s)]
---
## Context
[What situation prompted this decision? What constraints apply?
What alternatives were considered? Be specific — this section
is what future readers will need most.]
## Decision
[What we are doing, stated plainly in 1–3 sentences.]
## Consequences
**Positive:**
- [What this makes easier or better]
**Negative / trade-offs accepted:**
- [What this makes harder, slower, or more expensive]
- [What we are explicitly giving up]
**Risks:**
- [What could go wrong, and how we plan to detect it]
## Related
- ADR-NNN: [Link to any related decisions]
- [Link to the implementing PR or design doc]Lightweight design doc template
For larger changes that need more than an ADR:
# [Feature or System Name] — Design Doc
**Status:** Draft | In Review | Approved | Implemented
**Authors:** [Name(s)]
**Reviewers:** [Name(s)]
**Decision by:** YYYY-MM-DD
---
## Problem
[What are we trying to solve? Who is affected? What happens if we do nothing?]
## Goals
- [What this design must achieve]
## Non-goals
- [What this design explicitly does not address]
## Proposed Design
[How it works. Diagrams if helpful. Data model changes. API contracts.
Keep this section as short as it can be while remaining unambiguous.]
## Alternatives Considered
### Alternative A — [Name]
[Description and why it was rejected]
### Alternative B — [Name]
[Description and why it was rejected]
## Trade-offs
[What we are giving up. What gets harder. What risks we accept.]
## Rollout Plan
[How this gets deployed. Feature flags? Staged rollout? Migration steps?]
## Open Questions
- [ ] [Unresolved questions that must be answered before approval]Common Pitfalls
ADRs written after the decision. A retrospective ADR captures what happened but rarely captures why. The context section becomes vague because nobody remembers the constraints that were in play. ADRs are most valuable when written during the decision, not after.
The context section that's just a ticket link. "We needed to implement feature X per ticket ENG-1234" is not context. Context is the technical constraints, the alternatives that were ruled out, and the non-obvious factors that shaped the choice. A ticket link tells a reader nothing.
Consequences with only positives. Every architectural decision involves trade-offs. A consequences section that lists only benefits is either incomplete or dishonest. Future engineers will discover the negatives regardless — recording them upfront prevents surprises and shows the decision was made with clear eyes.
ADRs that are never read. A docs/decisions/ folder with 30 ADRs that nobody references is a documentation graveyard. Link to ADRs from PR descriptions, onboarding guides, and relevant code comments. ADRs need to be findable where engineers already work.
Treating every decision as ADR-worthy. If the bar is too low, the volume becomes unmanageable and engineers stop reading them. Reserve ADRs for decisions with genuine longevity — the ones a future engineer would genuinely need to know about to understand why the system is the way it is.
The ADR as a rubber stamp. Opening an ADR PR, getting one "+1" from a colleague without real review, and marking it accepted. The value of an ADR comes from the review process, not the document itself. If the decision wasn't examined from multiple angles, the ADR is recording a conclusion without the reasoning.