Architecture Decision Records
Three engineers re-debated Kafka versus RabbitMQ because the original choice lived in a departed architect's slide deck. Architecture Decision Records (ADRs) capture context, decision, and consequences in a few hundred words—optimized for the reader six months later asking "why on earth did we do this?" Michael Nygard's format spread because it fits pull requests, not because enterprises love paperwork.
Minimal template
# ADR-0007: Use PostgreSQL as system of record
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
## Status
Accepted
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
## Context
We need ACID transactions for billing and reporting joins.
Team knows Postgres; managed RDS available.
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
Decision:
PostgreSQL 16 on RDS as primary datastore.
Read replicas for analytics after Q3.
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
Consequences:
+ Strong consistency, mature tooling
- Horizontal write scaling limited; revisit sharding if >10k TPS
Number sequentially (0001, 0002). Title is searchable.
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
When to write
Open ADR PR before or alongside implementation PR for significant forks. Reviewers comment on decision merit separately from code style. Retroactive ADRs help onboarding when documenting existing system—label Accepted (documenting existing).
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
MADR variant
Markdown Any Decision Records add optional sections: decision drivers, considered options, pros/cons tables. Useful for contentious picks; skip for obvious choices.
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
Linking code
Reference ADR in commit message: Implement read replica routing (ADR-0007). Code search finds rationale. Conversely, ADR links to spike branch or POC PR.
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
Avoiding ADR graveyard
- Keep under one page
- Name real alternatives you rejected
- Record measurable consequences ("expect 20ms added latency")
- Review ADRs in quarterly architecture sync—supersede when reality diverges
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
Team workflow
Proposal PR → discussion → Accepted ADR merged → implementation PRs
Disagreements documented in PR comments become Context edits—not Slack loss.
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
adr-tools (adr new), Log4brains static site, or plain markdown. No mandatory SaaS.
ADR PR before or alongside implementation for significant forks. Status Superseded links forward—never delete history.
Keep under one page. Name real alternatives rejected. Record measurable consequences. Quarterly architecture sync supersedes stale ADRs when reality diverged.
adr-tools or Log4brains optional—markdown in repo is enough.
Validate this in staging with production-like data volume before declaring done. Capture metrics baseline the week before change and compare for seven days after—subtle regressions hide in aggregates until a large tenant hits the path. Update the on-call runbook with the failure signature and rollback command so responders need not rediscover steps during an incident.
Resources
- Documenting Architecture Decisions (Michael Nygard)
- adr.github.io
- MADR template
- Thoughtworks Technology Radar: ADRs
- AWS Prescriptive Guidance: ADR process
Frequently asked questions
What decisions deserve an ADR?
Decisions that are hard to reverse, affect multiple teams, or generate recurring debate: database choice, messaging bus, auth model, monolith vs services split, and public API versioning strategy. Skip ADRs for routine library bumps or formatting choices—over-documenting dilutes attention from decisions that actually constrain the system for years.
Where should ADRs live?
In the repository beside code—docs/adr/ or adr/ with numbered markdown files versioned with git. Link from README or internal wiki index. ADRs in Confluence alone drift from implementation; repo storage ties decisions to commits that implement them and survives tool migrations.
How do I handle superseded decisions?
Mark status Superseded by ADR-0012 with link; do not delete old ADRs. History explains why you left Postgres-only for read replicas and prevents new hires from relitigating settled tradeoffs without context. Accepted, Deprecated, Superseded statuses keep the log honest.
Hiring a senior Android / Flutter engineer?
I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.
Get in touch →