Best Practices for Architecture Decision Records (ADRs)
The meeting had been going for two hours. We were debating whether to use PostgreSQL or MongoDB for a new service. Arguments flew back and forth — relational integrity, flexible schemas, team familiarity, operational complexity.
Then someone mentioned: "Didn't we have this exact discussion last year for the user service?"
Silence. We had. A year ago, we'd spent a similar amount of time debating the same question, ultimately choosing PostgreSQL. But nobody remembered the reasoning. The engineer who led that discussion had left the company. So here we were, having the exact same debate from scratch.
That's when I discovered Architecture Decision Records (ADRs), and they've saved us countless hours of relitigating settled debates.
What's an ADR?
An ADR is a short document that captures a single architectural decision. Not a design document covering everything about a system, just one decision:
- What we decided
- Why we decided it
- What alternatives we considered
- What the consequences are
The format is deliberately lightweight. An ADR should fit on one page. If it's longer, you're probably documenting more than one decision.
The Anatomy of a Good ADR
After writing dozens of ADRs and reading hundreds more, I've found that the best ones follow a consistent structure:
Title and Number
Every ADR gets a sequential number and a concise title:
ADR-0042: Use PostgreSQL for Order Service
The number matters. It creates a timeline of decisions and makes ADRs easy to reference in discussions: "As we decided in ADR-42..."
Status
ADRs have lifecycle states:
- Proposed: Still under discussion
- Accepted: Decision made, we're following this
- Deprecated: No longer relevant (new ADR supersedes it)
- Rejected: We considered this but decided against it
The rejected status is particularly valuable. Sometimes you want to capture why you didn't do something, so future teams don't propose the same thing.
Context
This is where you describe the situation that prompted the decision. What problem are we solving? What constraints do we have? Who is affected?
## Context
The order service needs persistent storage for order data. We expect
to process 50,000 orders per day initially, growing to 500,000 within
two years. Orders have a well-defined structure but may need additional
metadata fields over time. The team has experience with both relational
and document databases.
Be specific about constraints. "We need ACID compliance" is much more useful than "we need reliability." Future readers need to understand the forces that shaped the decision.
Decision
State the decision clearly. Not "we might consider" or "we should explore" — what we actually decided.
## Decision
We will use PostgreSQL 15 as the primary database for the order service.
We chose PostgreSQL because:
- ACID compliance is required for financial order data
- JSON columns provide schema flexibility for metadata
- Our infrastructure team has operational experience with PostgreSQL
- Query patterns are well-suited to relational modeling
Notice this isn't just stating the decision but briefly explaining the reasoning. The next section goes into more detail, but even the decision section should be self-explanatory.
Alternatives Considered
This is the most underrated section. Documenting what you didn't choose is often as valuable as documenting what you did.
## Alternatives Considered
### MongoDB
Pros:
- Native JSON storage
- Simpler horizontal scaling
- Flexible schema evolution
Cons:
- Weaker consistency guarantees
- Team less familiar with operations
- Would require additional tooling for transactions
### DynamoDB
Pros:
- Fully managed, minimal operations
- Excellent scalability characteristics
Cons:
- Vendor lock-in to AWS
- Query patterns limited to partition/sort key access
- Cost unpredictable at high scale
When someone new joins the team and asks "why didn't we use MongoDB?", you have the answer. You don't need to schedule a meeting or find the person who made the original decision.
Consequences
Every decision has trade-offs. Be honest about them.
## Consequences
### Positive
- Strong data integrity guarantees
- Team can leverage existing PostgreSQL expertise
- Well-understood operational characteristics
### Negative
- Schema migrations require more planning than document stores
- Horizontal scaling more complex if we exceed single-node capacity
- Need to implement application-level sharding if we hit scale limits
### Risks
- May need to revisit if order volume exceeds 1M/day
- JSON column queries less efficient than native document stores
This section is about intellectual honesty. No decision is perfect. Acknowledging the downsides builds trust and helps future teams understand when they might need to revisit the decision.
When to Write an ADR
Not every technical choice needs an ADR. Use your judgment, but here are some guidelines:
Write an ADR When...
- The decision affects multiple teams or services
- The decision would be expensive to reverse
- You're choosing between multiple viable options
- Future team members might question the choice
- The decision resolves a significant technical debate
Don't Write an ADR When...
- The choice is obvious and uncontested
- The decision only affects one person or one file
- It's easily reversible without significant cost
- It's a standard pattern your team always follows
For example: "Which JSON library should we use?" probably doesn't need an ADR. "Should we use GraphQL or REST for our public API?" definitely does.
Real ADRs From Our Projects
Here are some actual ADRs we've written (simplified for this post):
ADR-0007: Event-Driven Communication Between Services
Context: Our microservices currently communicate synchronously via HTTP. This creates tight coupling and cascade failures when services are unavailable.
Decision: We will adopt an event-driven architecture using Apache Kafka for asynchronous communication between services.
Consequences:
- Services become more resilient to failures
- Eventual consistency instead of strong consistency
- Increased operational complexity (Kafka cluster management)
- Team needs training on event sourcing patterns
ADR-0015: Monorepo for Frontend Applications
Context: We have 5 frontend applications in separate repositories. Sharing code requires publishing packages. Developer experience suffers from version mismatches.
Decision: Consolidate all frontend applications into a single monorepo using Nx.
Alternatives Rejected:
- Keep separate repos with better package management: Rejected because coordination overhead remains
- Single repo without Nx: Rejected because build times would be prohibitive
Consequences:
- Simplified code sharing and consistency
- Single PR can update shared code and all consumers
- Larger repository requires better tooling for build caching
- Potential for unintended coupling between applications
Common Mistakes I've Made
Mistake 1: Writing ADRs After the Fact
The best time to write an ADR is during the decision process, not weeks later. When you write afterward, you forget the nuances, the alternatives you considered, and the specific constraints.
Now we write draft ADRs as part of the decision-making process. The discussion happens in the ADR document, not in Slack threads that disappear.
Mistake 2: Making Them Too Long
If your ADR is more than one page, you're probably:
- Documenting multiple decisions (split into multiple ADRs)
- Including implementation details (save that for design docs)
- Overexplaining obvious context
The discipline of brevity forces clarity.
Mistake 3: Not Linking Related ADRs
Decisions rarely exist in isolation. When we chose Kafka for event-driven communication (ADR-0007), that influenced our database choice (ADR-0042) because we could accept eventual consistency.
Cross-reference related ADRs:
## Related Decisions
- See ADR-0007 for why we accept eventual consistency
- Supersedes ADR-0003 which recommended MongoDB
Mistake 4: Abandoning the Practice
ADRs provide value over time. One or two ADRs don't help much. A corpus of 50+ ADRs, accumulated over years, becomes incredibly valuable. It's a searchable history of your architectural evolution.
The temptation is to stop writing them when things get busy. Resist it. The ten minutes spent writing an ADR will save hours of meetings later.
Making ADRs Part of Your Workflow
The hardest part isn't writing ADRs — it's making them a habit. Here's what works:
Store Them With the Code
Put ADRs in your repository, typically in docs/adr/ or docs/decisions/. This way:
- They're versioned with the code they describe
- They appear in code reviews
- They can't become orphaned in a wiki somewhere
Template It
Create a markdown template that everyone uses. This reduces friction and ensures consistency:
# ADR-NNNN: Title
## Status
Proposed | Accepted | Deprecated | Rejected
## Context
[What is the issue that we're seeing that is motivating this decision?]
## Decision
[What is the change that we're proposing and/or doing?]
## Alternatives Considered
[What other options did we consider?]
## Consequences
[What becomes easier or more difficult to do because of this change?]
Review ADRs Quarterly
Set a calendar reminder to review your ADRs every quarter:
- Are any decisions no longer relevant?
- Have circumstances changed that invalidate our assumptions?
- Are there undocumented decisions we should capture?
Link ADRs to Architecture Diagrams
This is where tools like Archyl shine. When you link an ADR to a specific component in your C4 diagram, anyone looking at that component can instantly see the decisions that shaped it.
"Why is this service talking to Kafka instead of directly to the database?" Click the linked ADR and find out.
Conclusion
Architecture Decision Records are one of those practices that seem like overhead until you need them. Then they're invaluable.
That two-hour meeting about PostgreSQL vs MongoDB? We ended it in ten minutes once someone found the original ADR. All the context was there — the constraints, the alternatives, the reasoning. We quickly confirmed that the original decision still applied and moved on.
Start small. Next time you make an architectural decision, take fifteen minutes to write an ADR. Put it in your repository. Six months from now, when someone asks "why did we do it that way?", you'll have the answer.
Learn more about architecture documentation: Introduction to C4 Model | Why Documentation Matters | Documenting User Flows