The Problem ADRs Solve
Every codebase accumulates decisions. Some are small: a naming convention, a logging format, a default timeout value. Others are structural: the choice of database, the service boundary design, the authentication approach. The structural ones shape every subsequent decision made in the system.
The problem is that architectural decisions, once made, become invisible. The database is PostgreSQL not because someone evaluated every database and documented why — it's PostgreSQL because it was the obvious choice, or because the team knew it, or because of a specific feature requirement that's long since been addressed. A developer joining the team two years later looks at the schema, asks "why are we using this partitioning approach?" and gets an answer that amounts to "historical reasons" or "ask James, he built this, but he left."
This is the problem Architecture Decision Records (ADRs) solve: they create a durable, searchable record of significant architectural decisions — what was decided, what the alternatives were, and why the decision went the way it did. Not every decision needs an ADR. The decisions that do are the ones where future developers will ask "why?" and deserve a better answer than git blame and archaeology.
What an ADR Is (and Isn't)
An ADR is a short document — typically 200-500 words — that records one architectural decision. It answers:
- What decision was made?
- What were the alternatives considered?
- Why was this option chosen over the alternatives?
- What are the expected consequences of this choice?
An ADR is not:
- A design document (which proposes a solution and invites feedback before a decision is made)
- Technical documentation of how something works (which explains the implementation, not the choice)
- A meeting minute (which records what was discussed, not what was decided and why)
- A specification (which tells implementers what to build, not why)
The key distinction: ADRs document decisions that have been made, not proposals for what to do. An ADR is written when the decision is settled — often immediately after, sometimes during. It records the outcome of a deliberation, not the deliberation itself.
The Origin of ADRs
The ADR format was proposed by Michael Nygard in a 2011 blog post, "Documenting Architecture Decisions," where he described a lightweight format for capturing decisions in a way that would survive personnel turnover, codebase evolution, and the passage of time.
Nygard's observation: most architecture documentation gets written in big batch design documents that become stale immediately after the first decision changes. The alternative is lightweight records — short, focused, co-located with the code they document — that stay current because they're easy to write and easy to update.
The format he proposed has been widely adopted, refined, and extended. The core structure has remained stable because it works.
The ADR Template
The standard ADR has five sections:
# ADR-[NNN]: [Short title]
**Status:** [Proposed | Accepted | Deprecated | Superseded by ADR-NNN]
## Context
[1-3 paragraphs describing the situation that led to this decision.
What problem needed to be solved? What constraints existed?
What was the state of the system or requirements at the time?]
## Decision
[1-2 paragraphs stating what was decided.
Use the form: "We will [do X]."
Be specific — this is the record of what was chosen.]
## Alternatives Considered
[Brief description of options that were evaluated but not chosen,
and the key reason each was not selected.]
## Consequences
[What happens as a result of this decision?
Include both positive and negative consequences.
What does this decision make easier? What does it make harder or foreclose?]
## References
[Optional: links to relevant documents, RFCs, issues, design docs, discussions.]
Filling in Each Section
Status: The lifecycle marker. "Proposed" means a decision is being discussed but not finalized. "Accepted" means the decision has been made and is in effect. "Deprecated" means the decision is no longer in force and a new approach has been adopted. "Superseded by ADR-NNN" provides a trail from the old decision to the new one.
Context: The hardest section to write and the most valuable to future readers. The context is what makes the decision legible years later — it explains the world as it appeared when the decision was made. What requirements drove this? What constraints existed (time, team expertise, budget, existing infrastructure)? What had already been decided that this decision had to work with?
Good context is specific: "At the time of this decision, our team had three engineers with deep PostgreSQL experience and no one with production experience in MongoDB. The system was expected to serve 50,000 users in year one, with potential to scale to 500,000 in year three. We had an existing PostgreSQL RDS instance that would be reused."
Poor context is vague: "We needed to choose a database. We considered the team's expertise and scaling requirements."
Decision: Concise and definitive. "We will use PostgreSQL as the primary relational database for all application data." Not "we considered PostgreSQL." Not "PostgreSQL was chosen." Active, specific, and past-committed.
Alternatives Considered: This is what makes the decision useful for future re-evaluation. When the context changes (new team expertise, new scaling requirements, new cost pressures), the alternatives section tells the next engineer what was evaluated and what the key objection was. If the key objection no longer applies, the ADR should be superseded.
You don't need exhaustive alternatives — the ones seriously considered are sufficient. For each alternative, one to three sentences: what it was and why it wasn't chosen.
Consequences: Both sides. Positive: what this decision enables. Negative: what it forecloses or makes harder. A decision record that acknowledges the trade-offs is more trustworthy and more useful than one that presents only the rationale for the choice.
Worked Example: Switching from REST to GraphQL
Setup: A team is transitioning their API layer from REST to GraphQL for their mobile clients. They decide to write an ADR.
# ADR-014: Adopt GraphQL for Mobile Client API Layer
**Status:** Accepted
## Context
Our mobile clients (iOS and Android, ~180,000 active users) are experiencing
significant performance problems due to API over-fetching. The REST endpoints
return full resource representations; mobile clients use 30-60% of the fields
returned. On a 3G connection, the extra payload adds 200-400ms per request.
The backend team has 4 engineers; 2 have GraphQL experience from prior roles.
The existing REST API serves 3 web clients as well as the mobile clients.
We cannot break the web client API. The decision must cover mobile-only
without disrupting the existing REST layer.
We evaluated this in Q4 2025 during the mobile performance sprint, with an
initial prototype built over two weeks.
## Decision
We will introduce a GraphQL API layer (using Apollo Server) for all new
mobile client endpoints. The existing REST API for web clients remains in
place and will not be migrated at this time.
The GraphQL layer runs as a separate service and calls the existing internal
REST services, acting as a BFF (Backend for Frontend). No business logic is
duplicated; all data access goes through existing services.
## Alternatives Considered
**Sparse fieldsets via REST (JSONAPI-style):** Would reduce over-fetching for
mobile without introducing a new query language. Rejected because it requires
client-side specification of every needed field per request type — significant
mobile client engineering effort with no runtime flexibility once fields are
specified.
**Migrate to a single GraphQL API for all clients:** Would eliminate the dual
API complexity long-term. Rejected for now because the web client codebases
are extensive; migrating them adds 6-8 weeks of frontend work to a mobile
performance sprint. Revisit in 2026 Q2 if mobile GraphQL adoption goes well.
**gRPC:** Better performance than GraphQL for internal service-to-service
communication but worse tooling for external mobile clients (no easy browser
support, limited ecosystem for iOS/Android). Not suitable as a public client API.
## Consequences
**Positive:**
- Mobile clients can request exactly the fields they need; eliminates over-fetching.
- Enables future real-time subscription support via GraphQL subscriptions.
- Type-safe schema serves as living API documentation for mobile teams.
- Apollo Studio provides query performance monitoring out of the box.
**Negative:**
- Two API layers to maintain (REST for web, GraphQL for mobile) adds operational complexity.
- Team must maintain GraphQL expertise; turnover risk if the two engineers with GraphQL experience leave.
- Query complexity attacks (overly expensive nested queries) require depth-limiting and cost-analysis middleware.
- N+1 query problem in GraphQL resolvers must be managed with DataLoader — additional implementation complexity.
## References
- [Mobile performance audit, November 2025](#)
- [GraphQL BFF prototype PR #1842](#)
- [Apollo Server documentation](https://www.apollographql.com/docs/apollo-server/)
Where to Store ADRs
ADRs belong with the code they document. The standard location is a docs/decisions/ directory at the root of the repository (or the service directory in a monorepo). File naming convention: NNN-short-title.md, where NNN is a sequential number (014-adopt-graphql-for-mobile.md).
The sequential number matters: it creates a chronological trail of decisions. ADR-020 that supersedes ADR-007 can link directly to ADR-007; readers can see the evolution of a decision.
In a monorepo: Place ADRs at the service or subsystem level if the decision is service-specific, or at the root level if it affects the whole monorepo. Don't put all ADRs at the root if they're actually scoped to individual services.
Discoverability: Add an ADR-README.md or index entry in your main docs/ directory that lists ADRs with their status and one-line description. Most ADR discovery happens through search (git grep, GitHub search), but an index makes the collection browsable.
When to Write an ADR
Not every decision needs one. The signal for "this needs an ADR":
The decision is reversible, but reversal would be expensive. Database choice, authentication approach, event sourcing vs. CRUD, service boundary design — changing these is possible but costs weeks of work. Record them.
The decision will affect future decisions. Any architectural choice that other decisions depend on — the choice of framework, the data model approach, the deployment target — is load-bearing in a way that justifies documentation.
The context will not be obvious to future engineers. If a developer joining in two years would look at this decision and wonder "why did they do it this way?", the decision needs documentation.
The decision required deliberation. If it was an obvious choice, documentation adds little. If multiple alternatives were seriously evaluated and one was chosen, the evaluation is the documentation.
Do not write an ADR for: naming conventions (put those in a contributing guide), library version pins (captured in package files), implementation details within a service (captured in inline comments or module docs), or decisions that will clearly be revisited within weeks.
Tools for ADR Management
adr-tools (github.com/npryce/adr-tools): CLI by Nat Pryce for creating, querying, and linking ADRs from the command line. Commands: adr new [title] creates a new ADR with the next sequential number; adr list lists all ADRs; adr supersede NNN [title] creates a new ADR and marks the old one as superseded. Installs via Homebrew.
Log4brains (github.com/thomvaill/log4brains): Generates a searchable static site from your ADR markdown files. Good for teams that want an ADR knowledge base that's browsable without navigating file trees.
Manual: For small teams, a docs/decisions/ directory with numbered markdown files and a manually maintained index is fully sufficient and has no setup overhead.
Key Takeaways
- ADRs document the why behind architectural decisions: they serve future engineers (and your future self) who inherit a system and need to understand not just what it does but why it was built this way.
- The context section is the most valuable: specific, dated context — what constraints existed, what was true about the team and system at the time — is what makes a decision legible after the world has changed.
- Include alternatives considered: when the context changes and the decision is being re-evaluated, the alternatives section shows what was already evaluated and why it was rejected — preventing the same deliberation from being repeated.
- Store ADRs with the code: co-location ensures they survive refactoring, repository migration, and wiki rot; a
docs/decisions/ directory in the repository is the standard.
- Write ADRs when the decision is settled, not before: ADRs record decisions that have been made; design docs propose and invite feedback; the distinction matters for tone, content, and the decision's lifecycle.
Conclusion
Architecture Decision Records are the lightweight alternative to documentation that never gets written and archaeology that wastes hours. A 300-400 word document written at decision time — context, what was chosen, alternatives not chosen, consequences — answers the question every new engineer eventually asks: "why does the system work this way?" The investment is ten minutes per significant decision. The return is hours of onboarding time saved per new team member, reduced re-litigation of settled decisions, and a legible trail of architectural intent that survives personnel turnover and codebase evolution.
Try WebSnips free — save technical documentation, RFC links, and architectural reference articles alongside your ADR notes, tag by technology and decision domain, and build the organized technical knowledge base that informs your next architecture decision.