ADR

Master this essential documentation concept

Quick Definition

Architecture Decision Record - a document that captures an important technical or architectural decision made during software development, including the context, options considered, and reasoning behind the choice.

How ADR Works

stateDiagram-v2 [*] --> Proposed: Engineer identifies architectural decision Proposed --> UnderReview: Team notified via pull request UnderReview --> Accepted: Consensus reached UnderReview --> Rejected: Better alternative identified UnderReview --> Proposed: Needs more context or options Accepted --> Deprecated: Technology obsoleted or superseded Accepted --> Superseded: New ADR replaces this one Rejected --> [*] Deprecated --> [*] Superseded --> [*]

Understanding ADR

Architecture Decision Record - a document that captures an important technical or architectural decision made during software development, including the context, options considered, and reasoning behind the choice.

Key Features

  • Centralized information management
  • Improved documentation workflows
  • Better team collaboration
  • Enhanced user experience

Benefits for Documentation Teams

  • Reduces repetitive documentation tasks
  • Improves content consistency
  • Enables better content reuse
  • Streamlines review processes

Keeping Your ADRs Alive After the Architecture Meeting Ends

Architecture Decision Records are only as useful as they are accessible. Many teams do the hard work of thinking through a decision carefully — weighing trade-offs, debating options, reaching consensus — but that reasoning lives entirely inside a recorded meeting or design review session. The ADR that gets written afterward, if it gets written at all, often captures the conclusion without the context.

This is where video-only approaches create a real gap. When a new engineer joins six months later and wants to understand why your team chose event sourcing over a traditional CRUD model, scrubbing through a two-hour architecture call is not a realistic option. The decision exists, but the reasoning is effectively lost.

Converting those architecture discussions into searchable documentation changes how your team maintains ADRs over time. You can extract the context, the rejected alternatives, and the constraints that shaped the decision — exactly the fields an ADR is meant to capture — directly from the conversation where those details were actually discussed. The result is an ADR that reflects how the decision was really made, not just a summary written from memory days later.

If your team records architecture reviews or design sessions, see how converting those recordings into structured documentation can strengthen your ADR practice →

Real-World Documentation Use Cases

Documenting a Database Migration from PostgreSQL to CockroachDB

Problem

A distributed systems team decides to migrate from PostgreSQL to CockroachDB for horizontal scalability, but six months later new engineers cannot understand why certain ORM patterns were abandoned or why specific consistency levels were chosen, leading to repeated debates and accidental regressions.

Solution

An ADR captures the evaluated alternatives (PostgreSQL with Citus, YugabyteDB, CockroachDB), the scalability requirements that drove the decision, the trade-offs accepted (e.g., no serializable isolation by default), and links to load test results that validated the choice.

Implementation

['Create ADR-0042-cockroachdb-migration.md in the /docs/adr directory using the MADR template, filling in the context section with current PostgreSQL pain points: single-region bottleneck at 50k writes/sec and cross-region latency above 200ms.', 'Document all three evaluated alternatives with a comparison table covering consistency model, operational complexity, licensing cost, and team familiarity scores from a spike conducted over two weeks.', 'Record the final decision with explicit consequences: accepted trade-offs like losing certain PostgreSQL-specific JSON operators and the plan to retrain the team on CockroachDB transaction semantics.', 'Link the ADR from the migration runbook, the database README, and the onboarding guide so any engineer touching the data layer encounters the decision rationale immediately.']

Expected Outcome

New engineers onboarding to the data team understand the database choice within their first week without scheduling architecture review meetings, and the team stops re-litigating the PostgreSQL vs CockroachDB debate in quarterly planning sessions.

Capturing the Adoption of Event Sourcing over CRUD for an Audit-Heavy Financial System

Problem

A fintech team adopts event sourcing mid-project to meet regulatory audit requirements, but the architectural shift is only communicated in a Slack thread and a single Confluence page. Eighteen months later, developers unfamiliar with event sourcing introduce CRUD-style mutations that corrupt the event log and violate compliance guarantees.

Solution

An ADR formally records that event sourcing was chosen over traditional CRUD with soft deletes specifically because SEC Rule 17a-4 requires immutable audit trails, documents the Axon Framework evaluation against custom Kafka-based solutions, and explicitly states that direct database mutations to the events table are prohibited.

Implementation

['Write ADR-0011-event-sourcing-financial-ledger.md with a context section that quotes the specific regulatory requirement (SEC 17a-4, FINRA 4370) and describes the failed audit finding that triggered the architectural review.', 'List the three options evaluated: CRUD with audit log tables, Change Data Capture with Debezium, and full event sourcing with Axon Framework, including a pros/cons matrix weighted by compliance fit, query complexity, and developer experience.', 'In the decision consequences section, explicitly call out forbidden patterns: no UPDATE or DELETE statements on the ledger_events table, and require all new aggregates to extend the BaseAggregateRoot class with enforcement via ArchUnit tests.', 'Set the ADR status to Accepted and add a supersedes field pointing to the previous ADR-0003 that had approved the CRUD approach, so the historical evolution is traceable.']

Expected Outcome

The ArchUnit tests enforcing the event sourcing constraints catch three violations in code review within the first month of adoption, and the team passes its next regulatory audit with complete immutable audit trail documentation referencing the ADR as evidence of intentional design.

Recording the Selection of a Micro-Frontend Architecture over a Monolithic React SPA

Problem

A platform team splits a monolithic React SPA into micro-frontends to allow four product teams to deploy independently, but the decision is only explained in a presentation deck that becomes stale. Teams building new features repeatedly ask why Module Federation was chosen over iframes or Web Components, and some teams start bypassing the architecture by importing across team boundaries.

Solution

An ADR documents the organizational driver (Conway's Law alignment with four independent squads), the technical evaluation of Webpack Module Federation versus single-spa versus iframes, and the explicit cross-team import boundary rules that must be enforced.

Implementation

['Draft ADR-0027-micro-frontend-module-federation.md with a context section explaining the deployment bottleneck: all four teams blocked on a single release train causing an average 3-week delay from feature-complete to production.', 'Document the spike results comparing Module Federation (chosen), single-spa, and iframes across criteria: runtime integration, shared dependency management, team autonomy, and SEO impact for the marketing pages.', 'Define the architectural constraints section with explicit rules: no direct imports across micro-frontend boundaries, all shared state must go through the event bus contract defined in the shared-contracts package, and each team owns exactly one remote entry point.', "Attach the ADR to the repository's CONTRIBUTING.md and configure a Danger.js rule that posts the ADR link in any pull request that attempts cross-boundary imports detected by ESLint's import/no-restricted-paths rule."]

Expected Outcome

Cross-boundary import violations drop to zero within two sprints of publishing the ADR with automated enforcement, and new engineers joining any of the four product teams understand the micro-frontend boundaries and rationale within their first pull request review.

Documenting the Rejection of GraphQL in Favor of REST with OpenAPI for a Public Partner API

Problem

An API platform team evaluates GraphQL for a new partner integration API but ultimately rejects it. Without a formal record, the decision appears arbitrary to new team members and external partners, leading to recurring proposals to switch to GraphQL in every quarterly roadmap review and wasted time re-evaluating the same trade-offs.

Solution

An ADR with Rejected status documents exactly why GraphQL was not chosen for this specific context—partner SDK generation complexity, lack of GraphQL expertise in partner engineering teams, and the need for predictable rate limiting per endpoint—preserving the reasoning so future proposals can reference concrete constraints rather than starting from scratch.

Implementation

['Create ADR-0019-rest-openapi-partner-api.md and explicitly set the status to Rejected for GraphQL, making clear this ADR documents a rejected option to explain the chosen path of REST with OpenAPI 3.1 specification.', 'Write a detailed context section describing the three partner integration scenarios evaluated: bulk data sync, real-time webhooks, and ad-hoc queries, noting that only the ad-hoc query case favored GraphQL while the other two were better served by REST.', 'In the consequences section, document the specific GraphQL drawbacks encountered during the two-week proof of concept: client SDK generation required graphql-code-generator with custom plugins adding 3 weeks of partner onboarding work, and per-query rate limiting required a custom cost-analysis middleware with no off-the-shelf solution.', 'Add a revisit trigger clause stating the decision should be re-evaluated if more than 40% of partners request flexible querying capabilities or if the team adopts a GraphQL gateway like Apollo Router that solves the SDK generation problem.']

Expected Outcome

The quarterly roadmap review no longer includes GraphQL re-evaluation proposals because product managers and engineers can read the ADR's revisit trigger clause and confirm the conditions have not been met, saving an estimated two hours of meeting time per quarter per team.

Best Practices

âś“ Write ADRs at the Moment of Decision, Not in Retrospect

ADRs written weeks or months after a decision is implemented lose the nuance of the options that were genuinely on the table and the specific constraints that existed at that moment. The context section becomes vague and the rejected alternatives are often forgotten or misrepresented. Capturing the ADR during the decision-making process—ideally as a pull request opened before implementation begins—ensures the reasoning reflects actual deliberation rather than post-hoc rationalization.

âś“ Do: Open an ADR pull request in Proposed status when the architectural question is first identified, use it as the artifact for team discussion and iteration, and merge it to Accepted only when the team reaches consensus and implementation is approved.
âś— Don't: Do not write ADRs as retrospective documentation after the code is already merged and deployed, as this produces justification documents rather than genuine decision records and loses the rejected alternatives that shaped the choice.

âś“ Store ADRs as Numbered Markdown Files in the Application Repository

ADRs stored in a separate wiki, Confluence space, or shared drive become disconnected from the codebase they document and are frequently missed during onboarding or code review. Placing ADRs as sequentially numbered files (e.g., docs/adr/0042-use-redis-for-session-storage.md) in the same repository as the code ensures they appear in git history, are discoverable via grep and IDE search, and can be linked directly in code comments and pull requests.

âś“ Do: Use a consistent naming convention like NNNN-short-hyphenated-title.md, store files under docs/adr/ or a dedicated adr/ directory at the repository root, and add a README index file in that directory listing all ADRs with their current status.
âś— Don't: Do not store ADRs exclusively in Confluence, Notion, or Google Docs where they cannot be linked from code comments, do not appear in repository search, and are frequently lost when wiki spaces are reorganized or access permissions change.

âś“ Always Document Rejected Alternatives with Specific Reasons

The most common ADR anti-pattern is listing alternatives without explaining why they were rejected, reducing the document to a superficial catalog rather than a decision record. Future engineers encountering the same alternatives—a new Redis version, a new framework release—need to know whether the rejection was due to a fundamental mismatch or a temporary limitation that may no longer apply. Specific rejection reasons also prevent teams from re-evaluating the same options without new information.

âś“ Do: For each rejected alternative, write at least two sentences explaining the specific technical, organizational, or economic reason it was not chosen, and note whether the reason is permanent (fundamental architectural mismatch) or time-bound (team lacked expertise in Q3 2023).
âś— Don't: Do not write rejection reasons like 'too complex' or 'not suitable for our use case' without quantifying the complexity cost or specifying which aspect of the use case was incompatible, as these vague reasons provide no signal to future engineers evaluating whether the constraint still applies.

âś“ Supersede Old ADRs Rather Than Editing Them In Place

ADRs are immutable records of decisions made at a specific point in time with specific context. Editing an existing ADR to reflect a new decision destroys the historical record and makes it impossible to understand how the architecture evolved. When a decision changes, the correct process is to create a new ADR that explicitly supersedes the old one, update the old ADR's status to Superseded with a link to the new ADR, and leave the original content intact.

âś“ Do: When a technology choice changes, create a new ADR with a 'Supersedes: ADR-NNNN' field in the header, update the original ADR's status line to 'Superseded by ADR-MMMM' with a date, and keep all original content so the full decision history remains readable.
âś— Don't: Do not edit the context, decision, or consequences sections of an accepted ADR to reflect new information or a changed decision, as this rewrites history and prevents teams from understanding why the architecture looks the way it does at any point in its evolution.

âś“ Link ADRs from Code, READMEs, and Runbooks at the Point of Relevance

An ADR that exists but is never discovered provides no value. Engineers reading a confusing piece of code, a non-obvious configuration choice, or an unusual deployment constraint need to encounter the ADR at the moment they have the question, not only when they think to search for it. Proactive linking from code comments, module READMEs, and operational runbooks turns ADRs from passive archives into active documentation that surfaces at the right moment.

âś“ Do: Add a comment like '// See ADR-0031 for why we use optimistic locking here instead of database transactions' directly above non-obvious code patterns, include an 'Architecture Decisions' section in module-level README files listing relevant ADRs, and reference ADRs in runbook steps that implement consequences of architectural choices.
âś— Don't: Do not rely on engineers proactively searching the docs/adr directory to discover relevant decisions, as most engineers will only search for ADRs after they have already made a mistake or spent significant time confused by a non-obvious design choice.

How Docsie Helps with ADR

Build Better Documentation with Docsie

Join thousands of teams creating outstanding documentation

Start Free Trial