Architecture Decision Records (ADR): The Complete Guide
Every software system is shaped by hundreds of decisions. PostgreSQL over MongoDB. REST over GraphQL. Monolith over microservices. Event-driven over request-response. Each choice constrains future choices, and together they define the architecture.
The problem is that decisions are invisible. Code shows what was built, not why it was built that way. Six months after choosing PostgreSQL, nobody remembers whether the team considered DynamoDB, what the performance requirements were, or why eventual consistency was unacceptable. The decision is baked into the code, but the reasoning is lost.
Architecture Decision Records (ADRs) solve this by capturing each significant decision in a short, structured document. They're one of the highest-leverage documentation practices in software engineering -- simple to adopt, cheap to maintain, and invaluable when you need them.
This guide covers everything from the basics to advanced practices: what ADRs are, how to write them, templates you can adopt today, common pitfalls, and how to integrate ADRs into your workflow with modern tooling.
What is an Architecture Decision Record?
An Architecture Decision Record is a short document that captures a single architectural decision. The emphasis is on single and short:
- Single: One ADR, one decision. "Use PostgreSQL for the order service" is one ADR. "Set up the entire database strategy" is a design document, not an ADR.
- Short: An ADR should fit on one page. If it's longer, you're likely documenting multiple decisions or including too much implementation detail.
The concept was popularized by Michael Nygard in a 2011 blog post. Since then, ADRs have been adopted by organizations ranging from startups to governments. The UK Government Digital Service, Spotify, and countless engineering teams use ADRs as a standard practice.
What ADRs Capture
Every ADR answers four fundamental questions:
- What was the context? What situation or problem prompted this decision?
- What did we decide? What is the specific architectural choice we made?
- What alternatives did we consider? What other options were on the table?
- What are the consequences? What trade-offs, risks, and implications come with this decision?
That's it. Four questions. A well-written ADR can answer all four in less than a page.
What ADRs Are Not
- Not design documents. ADRs don't describe how something is implemented. They describe why a particular approach was chosen.
- Not RFCs. RFCs (Request for Comments) are proposals for discussion. ADRs document concluded decisions (though an ADR can start as a proposal and transition to accepted).
- Not meeting notes. ADRs capture the outcome, not the discussion that led to it.
- Not comprehensive documentation. ADRs complement architecture diagrams, API specs, and runbooks. They don't replace them.
The Standard ADR Template
Multiple ADR templates exist, but most are variations of the same core structure. Here's a practical template that balances completeness with brevity:
# ADR-NNNN: [Short Title Describing the Decision]
## Status
[Proposed | Accepted | Deprecated | Superseded by ADR-XXXX]
## Date
[YYYY-MM-DD]
## Context
[Describe the situation. What problem are we solving? What constraints
exist? What forces are at play? Be specific -- include numbers, deadlines,
team capabilities, and technical requirements where relevant.]
## Decision
[State the decision clearly and concisely. Use active voice:
"We will use X" not "X should be considered."]
## Alternatives Considered
### [Alternative 1]
- Pros: ...
- Cons: ...
- Why rejected: ...
### [Alternative 2]
- Pros: ...
- Cons: ...
- Why rejected: ...
## Consequences
### Positive
- [What becomes easier or better]
### Negative
- [What becomes harder or worse]
### Risks
- [What could go wrong]
## Related Decisions
- [Links to related ADRs]
Breaking Down Each Section
Status tracks the lifecycle of a decision. The typical flow is: Proposed -> Accepted. If circumstances change, an ADR becomes Deprecated or Superseded by a newer ADR. Importantly, you should never delete ADRs -- even rejected decisions are valuable because they prevent future teams from reconsidering options that were already evaluated.
Date establishes when the decision was made. This provides temporal context: "We chose this technology in 2024 when our scale was X. Now that our scale is 10X, we should revisit."
Context is the most important section. A well-written context section gives future readers enough information to understand why this decision made sense at the time, even if circumstances have since changed. Include specific numbers ("we process 50K orders per day"), constraints ("must comply with PCI-DSS"), and team factors ("three engineers have PostgreSQL experience, none have MongoDB experience").
Decision should be unambiguous. "We will use PostgreSQL 16 as the primary data store for the order service" is good. "We should probably consider a relational database" is not an ADR -- it's a suggestion.
Alternatives Considered is the section that saves the most time long-term. When a new engineer asks "why didn't we use MongoDB?", the answer is right here. When the team revisits the decision a year later, they can see what was evaluated and why it was rejected. Without this section, teams relitigate the same debates endlessly.
Consequences is about intellectual honesty. Every decision has trade-offs. Acknowledging the downsides builds trust and helps future teams understand when circumstances might warrant revisiting the decision.
A Complete ADR Example
Here's a realistic ADR that demonstrates the template in practice:
# ADR-0023: Use Apache Kafka for Inter-Service Communication
## Status
Accepted
## Date
2025-11-15
## Context
Our platform has grown from 3 microservices to 12 over the past year.
Services currently communicate synchronously via HTTP REST calls. This
creates several problems:
- Cascade failures: when the inventory service is down, the order
service can't process orders, even though inventory checks could
be eventual.
- Tight coupling: services need to know each other's API contracts
and endpoints.
- Performance bottlenecks: some operations trigger chains of 4-5
synchronous calls, adding latency.
We process approximately 100K events per day. We expect this to grow
to 500K within 12 months. The team has 8 backend engineers, 2 of whom
have prior Kafka experience.
## Decision
We will adopt Apache Kafka as the primary mechanism for asynchronous
inter-service communication. Synchronous HTTP will remain for
request/response patterns where the caller needs an immediate result
(e.g., authentication checks).
We will use Confluent Cloud as the managed Kafka provider to minimize
operational overhead.
## Alternatives Considered
### RabbitMQ
- Pros: Simpler to operate, lower learning curve, supports multiple
messaging patterns (pub/sub, point-to-point, routing).
- Cons: Less suitable for event sourcing patterns we plan to adopt.
Weaker replay/rewind capabilities. Community momentum has shifted
toward Kafka for event-driven architectures.
- Why rejected: We anticipate needing event replay for audit and
debugging. Kafka's log-based architecture is better suited.
### AWS SQS + SNS
- Pros: Fully managed, no infrastructure to maintain, tight AWS
integration.
- Cons: Vendor lock-in to AWS. Limited message ordering guarantees.
No built-in stream processing (would need Kinesis or Lambda).
Higher per-message cost at our projected volume.
- Why rejected: We want to avoid deepening AWS lock-in, and we need
ordered message delivery for financial events.
### Keep Synchronous HTTP (with circuit breakers)
- Pros: No new infrastructure. Team already familiar. Circuit
breakers address cascade failures.
- Cons: Doesn't solve tight coupling. Latency still accumulates
across call chains. Circuit breakers are a band-aid, not a
solution to the fundamental coupling problem.
- Why rejected: Addresses symptoms, not root cause.
## Consequences
### Positive
- Services become decoupled: producers don't need to know consumers.
- Cascade failures eliminated for async workflows.
- Event replay enables powerful debugging and audit capabilities.
- Foundation for event sourcing patterns in future services.
### Negative
- Operational complexity increases (Kafka cluster, schema registry,
consumer group management). Mitigated by using Confluent Cloud.
- Team needs training on Kafka concepts and patterns.
- Eventual consistency replaces strong consistency for async flows.
Some workflows need redesign.
- Debugging distributed async flows is harder than tracing synchronous
HTTP calls. We'll need distributed tracing (see ADR-0024).
### Risks
- If message volume exceeds Confluent Cloud pricing tiers, costs
could increase significantly. Monitor and set alerts.
- Schema evolution across services requires discipline. Plan to
adopt Avro with schema registry.
## Related Decisions
- ADR-0024: Adopt OpenTelemetry for Distributed Tracing
- ADR-0018: Service Communication Contracts (superseded by this ADR)
This ADR is about 400 words. It took maybe 20 minutes to write. It will save hours of meetings over the next few years.
When to Write an ADR
Not every technical choice needs an ADR. Choosing between two JSON libraries doesn't warrant one. But some decisions absolutely do.
Write an ADR When:
- The decision affects the system's structure. Anything that changes how services communicate, where data lives, or how components are organized.
- The decision is costly to reverse. Choosing a database, a messaging system, or a deployment platform. If undoing this decision takes more than a sprint, document why you made it.
- Multiple viable options exist. If the choice is obvious, no ADR needed. If you debated between three options, capture the reasoning.
- The decision crosses team boundaries. Any architectural choice that affects other teams should be documented so they understand the rationale.
- Future you might question the choice. If there's any chance someone (including future you) will ask "why did we do this?", write it down now.
Skip the ADR When:
- The choice follows an established team standard (e.g., "we always use Go for backend services" doesn't need a new ADR for each service)
- The decision is trivially reversible (renaming a variable, choosing a code formatter)
- The decision is purely cosmetic (code style, naming conventions -- these belong in a style guide)
ADR Lifecycle and Governance
The Lifecycle
ADRs have a natural lifecycle:
- Draft/Proposed: Someone identifies a decision that needs to be made and writes a draft ADR. The team discusses.
- Accepted: The team agrees on the decision. The ADR status changes to Accepted.
- Active: The decision is in effect. The ADR serves as reference documentation.
- Superseded: A new decision replaces this one. The old ADR gets a "Superseded by ADR-XXXX" status. The new ADR references the old one.
- Deprecated: The decision is no longer relevant (perhaps the system it applied to was decommissioned).
Important: never delete ADRs. Even deprecated or superseded ones are valuable. They form a timeline of architectural evolution.
Numbering
Use sequential numbers: ADR-0001, ADR-0002, etc. The number provides chronological ordering and makes ADRs easy to reference in conversations: "as decided in ADR-42."
Some teams use date-based numbering (ADR-2026-03-27-kafka) but sequential numbers are simpler and more widely used.
Review Cadence
Set a quarterly reminder to review your ADRs:
- Are any accepted decisions no longer valid?
- Have constraints changed that invalidate assumptions?
- Are there decisions the team made informally that should be captured?
This review prevents ADR rot and keeps the collection current.
Where to Store ADRs
The most common approaches, in order of recommendation:
In the Code Repository
Store ADRs in docs/adr/ or docs/decisions/ within your repository. This is the most popular approach and for good reason:
- ADRs are version-controlled alongside the code they describe
- They appear in pull requests and code reviews
- They can't be orphaned in a wiki nobody visits
- They're discoverable via
grepor search
Convention: one markdown file per ADR, named with the number and a slug:
docs/adr/
0001-use-postgresql-for-orders.md
0002-adopt-event-driven-architecture.md
0003-monorepo-for-frontend.md
In a Dedicated Architecture Tool
Tools like Archyl provide built-in ADR management with additional capabilities:
- Link ADRs directly to C4 model elements (containers, components, relationships)
- Search and filter ADRs across all projects
- Track ADR status and lifecycle
- Connect ADRs to conformance rules that enforce the decision
The key advantage of an architecture tool is context. When a developer looks at the PostgreSQL container in a C4 diagram, they can click through to the ADR that explains why PostgreSQL was chosen. The decision and the architecture are connected, not siloed.
In a Wiki (Not Recommended)
Wikis (Confluence, Notion, etc.) are where ADRs go to be forgotten. They're disconnected from the code, hard to discover, and rarely maintained. If you must use a wiki, at least cross-reference ADRs from the code repository.
Integrating ADRs Into Your Workflow
Make ADRs Part of Pull Requests
For significant architectural changes, require an ADR as part of the pull request. Add a section to your PR template:
## Architecture Impact
- [ ] No architectural changes
- [ ] ADR created/updated: [link]
This normalizes ADR creation and ensures decisions are documented when they're made, not weeks later when the context has faded.
Use ADRs in Architecture Reviews
During architecture reviews or design discussions, reference existing ADRs. "Before we redesign this, let's check what ADR-15 says about why we chose this approach." This gives ADRs visibility and reinforces the habit of documenting decisions.
Connect ADRs to Architecture Diagrams
This is where ADRs become truly powerful. When an ADR is linked to a specific element in your C4 model, it creates a navigable knowledge graph:
- Click on the Kafka container in your Container diagram -> see ADR-0023 explaining why Kafka was chosen
- Click on the PostgreSQL database -> see ADR-0001 explaining the database selection
- Click on the API Gateway -> see ADR-0012 explaining why Kong was chosen over custom routing
In Archyl, you can link ADRs to any C4 element -- systems, containers, components, or relationships. This connection means architectural decisions aren't floating documents; they're anchored to the specific parts of the architecture they affect.
Automate What You Can
Several tools can reduce the friction of ADR management:
- adr-tools (by Nat Pryce): A command-line tool for creating and managing ADRs in a repository. Run
adr new "Use Kafka for messaging"to generate a new ADR from a template. - Log4brains: Generates a searchable, browsable website from your ADR markdown files.
- Archyl: Manages ADRs with linking to C4 elements, status tracking, and cross-project search.
Advanced ADR Practices
Lightweight ADRs (LADRs)
Some teams find even the standard template too heavy. A Lightweight ADR is just three sentences:
In the context of [situation],
we decided [decision],
to achieve [goal],
accepting [trade-off].
Example:
In the context of needing inter-service communication that tolerates
service downtime, we decided to use Apache Kafka via Confluent Cloud,
to achieve service decoupling and event replay capability, accepting
increased operational complexity and eventual consistency.
This format works well for decisions that are important enough to document but don't warrant a full ADR.
Decision Logs
A decision log is a single document that lists all ADRs in chronological order with one-line summaries. It serves as an index:
| # | Date | Decision | Status |
|---|---|---|---|
| 23 | 2025-11-15 | Use Kafka for inter-service communication | Accepted |
| 24 | 2025-11-20 | Adopt OpenTelemetry for distributed tracing | Accepted |
| 25 | 2025-12-01 | Migrate from REST to gRPC for internal APIs | Proposed |
This gives a quick overview of all decisions without opening individual ADR files.
ADRs for Non-Technical Decisions
ADRs aren't limited to technology choices. Teams use them for:
- Process decisions: "We will do pair programming for security-critical code"
- Organizational decisions: "The platform team owns all infrastructure containers"
- Vendor decisions: "We will use Datadog for monitoring instead of building in-house"
If the decision is significant and reversible-but-costly, an ADR is appropriate regardless of whether it's strictly "architectural."
Common Pitfalls
Writing ADRs After the Fact
The best time to write an ADR is during the decision-making process. Writing one weeks later means you've forgotten the nuances, the alternatives you considered, and the constraints that existed. Make ADR writing part of the decision process, not an afterthought.
Making Them Too Long
If your ADR exceeds one page, you're probably documenting multiple decisions (split them) or including implementation details (save those for a design doc). The discipline of brevity forces clarity.
Not Documenting Rejected Alternatives
The "Alternatives Considered" section is the most valuable part of an ADR long-term. Without it, future engineers will propose the same alternatives, unaware they were already evaluated and rejected. Always explain what you didn't choose and why.
Abandoning the Practice
One or two ADRs don't provide much value. Fifty ADRs accumulated over two years become an invaluable knowledge base. The temptation to stop writing ADRs when things get busy is strong. Resist it. The 15 minutes you spend writing an ADR will save hours of meetings later.
Not Reviewing or Updating Status
An ADR collection where half the decisions are outdated is misleading. Schedule quarterly reviews. Mark superseded decisions. Keep the collection trustworthy.
Why ADRs Matter More in the AI Era
As AI agents become active participants in software development, ADRs take on new importance. An AI agent writing code can read your ADRs and understand:
- Why certain technologies were chosen (and should continue to be used)
- What alternatives were rejected (and shouldn't be re-proposed)
- What constraints exist (compliance requirements, performance thresholds)
- What trade-offs were accepted (eventual consistency, vendor dependencies)
Through Archyl's MCP server, AI agents like Claude Code can access your ADRs before making architectural suggestions. Instead of proposing MongoDB for a service where you've already documented why PostgreSQL was chosen, the agent respects the existing decision -- or explicitly flags when it thinks the decision should be revisited.
This makes ADRs not just documentation for humans, but guardrails for AI.
Getting Started Today
If your team doesn't use ADRs yet, start with these three steps:
Pick one recent decision. Think of an architectural choice your team debated in the last month. Write an ADR for it using the template above. It should take 15-20 minutes.
Store it in your repo. Create a
docs/adr/directory and add the file. Include it in your next pull request so the team sees it.Make it a habit. Add an "Architecture Impact" checkbox to your PR template. Discuss ADRs in your next architecture meeting. The practice builds momentum once the team sees the value.
The next time someone asks "why did we do it that way?" -- and they will -- you'll have the answer.
Explore more about architecture documentation: What is the C4 Model? | ADR Best Practices | AI-Powered Architecture Discovery. Or try Archyl free to manage ADRs linked directly to your C4 model.