Developer Knowledge

How to Write Architecture Decision Records

How to write architecture decision records (ADRs) — a practical guide for engineers and tech leads who want to document the significant architectural

Back to blogAugust 16, 20267 min read
acwrite-architecture-decision-records-best-practiceswrite-architecture-decision-records-templatewrite-architecture-decision-records-tools

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:

  1. What decision was made?
  2. What were the alternatives considered?
  3. Why was this option chosen over the alternatives?
  4. 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


---

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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.

To go deeper, check out AI Knowledge Management in 2025.

Keep reading

More WebSnips articles that pair well with this topic.

Developer KnowledgeAugust 17, 202610 min read

How to Build a Knowledge Base for a Dev Team

How to build a knowledge base for a dev team — a practical guide for engineering teams who want a shared knowledge system that engineers actually use

acbuild-a-knowledge-base-for-a-dev-team-best-practicesbuild-a-knowledge-base-for-a-dev-team-templatebuild-a-knowledge-base-for-a-dev-team-tools
Read article
Developer KnowledgeAugust 17, 20269 min read

How to Document a Microservices Architecture

How to document a microservices architecture — a practical guide for engineering teams navigating service sprawl, where the challenge is not documenting

acdocument-a-microservices-architecture-best-practicesdocument-a-microservices-architecture-templatedocument-a-microservices-architecture-tools
Read article
Developer KnowledgeAugust 17, 20268 min read

How to Keep a Changelog Developers Trust

How to keep a changelog developers trust — a practical guide for engineering teams who want a CHANGELOG.md that consumers of their API or library actually

ackeep-a-changelog-developers-trust-best-practiceskeep-a-changelog-developers-trust-templatekeep-a-changelog-developers-trust-tools
Read article
Developer KnowledgeAugust 17, 20269 min read

How to Save and Organize Design Docs

How to save and organize design docs — a practical guide for engineers and engineering teams who want their design documents to remain findable, useful

acsave-and-organize-design-docs-best-practicessave-and-organize-design-docs-templatesave-and-organize-design-docs-tools
Read article
Developer KnowledgeAugust 17, 20268 min read

How to Take Notes During Code Review

How to take notes during code review — a practical guide for engineers who want to get more from code review than the immediate feedback loop: building a

actake-notes-during-code-review-best-practicestake-notes-during-code-review-templatetake-notes-during-code-review-tools
Read article
Developer KnowledgeAugust 17, 20269 min read

How to Track Tech-Debt Decisions

How to track tech-debt decisions — a practical guide for engineering teams who want to manage their technical debt as intentional trade-offs rather than

actrack-tech-debt-decisions-best-practicestrack-tech-debt-decisions-templatetrack-tech-debt-decisions-tools
Read article