Architecture Decision Records (ADR): Template and Examples
An architecture decision record is a short Markdown file in your repository that says what the team decided about the system’s structure, why, and what follows from it. Nygard’s five-part template, the MADR alternative, numbering and superseding, a filled example, and how to make coding agents read them.
8 min read
An architecture decision record template needs five parts: a numbered title, a status, the context that forced the choice, the decision itself written as “We will…”, and the consequences, good and bad. Keep each record to a page or two, save it as a Markdown file in the repository next to the code it governs, number it in sequence and never reuse a number. When the decision changes, do not edit the old record: write a new one that supersedes it and mark the old one superseded. Below are two templates to copy, a filled example, the numbering and superseding rules, and how to get AI coding agents to read the records before they change the code.
This page is about the ADR as a file in a code repository. A project-wide list of every decision, including product and commercial ones, is a different document with its own page: the decision log template.
Nygard’s format: five parts
The format most teams start from comes from Michael Nygard’s 2011 post Documenting Architecture Decisions (opens in a new tab). He proposed keeping records only for “architecturally significant” decisions, those that affect the structure, non-functional characteristics, dependencies, interfaces or construction techniques, and storing each one in the repository as a short text file under a path such as doc/arch/adr-NNN.md.
- Title: a short noun phrase with the number, such as “ADR 9: LDAP for Multitenant Integration”.
- Context: the forces at play, technical, political, social and local to the project, written as neutral facts. If they pull against each other, say so.
- Decision: the response to those forces, in full sentences and the active voice: “We will…”.
- Status: proposed while people are still agreeing, accepted once they have, and deprecated or superseded later, with a reference to the replacement.
- Consequences: what the world looks like after the decision, all of it. Nygard is explicit that negative and neutral consequences go here as well as the positive ones.
He also asked that each record read as a conversation with a future developer: full sentences in paragraphs, one or two pages long. That reader is the whole point. They arrive months later, find something that looks odd, and need to know whether the reason still holds before they change it.
An ADR template you can copy
# ADR NNNN: [decision, as a short noun phrase] Status: Proposed | Accepted | Deprecated | Superseded by ADR NNNN Date: [Month day, year] Deciders: [names and roles of the people who made the call] Supersedes: [ADR NNNN, or none] ## Context [The forces at play: requirements, constraints, deadlines, what exists today. Facts, not arguments. Link the issue or task that raised it.] ## Decision We will [the decision, in one or two full sentences]. ## Consequences - Good: [what gets easier] - Bad: [what gets harder, and what it costs] - Neutral: [what changes but is neither] - Follow-up work: [tasks this creates, with their refs]
The Deciders and Supersedes lines are additions to Nygard’s five parts, and worth the two lines. A record that does not say who decided invites anyone to overrule it; one that does not point back to what it replaced breaks the chain a reader follows from an old commit to the rule that holds today.
A filled example
# ADR 0012: Background jobs in Postgres, not a separate queue Status: Accepted Date: August 18, 2026 Deciders: Ana Ruiz (tech lead), Marcus Lee (platform) Supersedes: none ## Context We send about 40,000 emails and webhooks a day from request handlers, and failures are lost. We need retries and a record of what ran. We already run Postgres with backups and monitoring; we run nothing else stateful. Two engineers are on call. ## Decision We will run background jobs from a jobs table in our existing Postgres database, using row locks so each job is taken once. We will not add a separate message broker at this time. ## Consequences - Good: one database to back up, monitor and restore. A job and the row it changes can commit in one transaction. - Bad: job volume adds load to the main database. Above roughly ten times today's volume we expect to revisit this. - Neutral: workers are a new process type in every deployment. - Follow-up work: ENH-231 jobs table and worker; ENH-232 retry with backoff; FET-233 admin page listing failed jobs.
Notice the Bad line names the condition under which the decision should be reopened. A future reader who sees traffic at twelve times today’s volume knows the record expected them, and that proposing ADR 0031 to replace it is the intended next step, not a rebellion.
MADR: the longer alternative
When a decision has several real options and people need to see the trade-offs, MADR (opens in a new tab) (Markdown Architectural Decision Records) gives more structure. Version 4.0.0 was released on September 17, 2024. Its template has a Context and Problem Statement, Decision Drivers, Considered Options, a Decision Outcome written as “Chosen option: …, because …”, Consequences, an optional Confirmation section that says how compliance will be checked, the pros and cons of each option, and More Information. Optional front matter holds the status, date, decision-makers, and who was consulted and informed.
--- status: accepted date: 2026-08-18 decision-makers: Ana Ruiz, Marcus Lee --- # Background jobs in Postgres, not a separate queue ## Context and Problem Statement Emails and webhooks sent from request handlers are lost on failure. How should we run work that must be retried? ## Considered Options * Jobs table in the existing Postgres database * Managed message broker * Cron scripts ## Decision Outcome Chosen option: "Jobs table in the existing Postgres database", because it adds no new stateful service for a two-person on-call. ### Consequences * Good, because a job and its data commit together * Bad, because job load lands on the main database ### Confirmation Code review rejects new direct broker clients; see ENH-231.
Pick one format per repository and keep it. Nygard’s is faster to write, so more decisions get recorded; MADR is better when the rejected options are the part future readers will argue about.
Numbering, files and the index
- Number in sequence and never reuse a number, even for a record that was rejected. A number quoted in a pull request two years from now must still point to the same text.
- Use four digits and a dashed title in the file name, as MADR does:
docs/decisions/0012-background-jobs-in-postgres.md. Files then sort in order in any file browser. - Keep a one-page index,
docs/decisions/README.md, with one line per record: number, title, status. It is what people skim, and it is what you point an agent at. - Keep rejected records. A rejected ADR is the answer to “did anyone consider X?”, and it stops the same proposal coming back every quarter.
- Link both ways. The pull request that implements a decision cites the ADR number; the ADR lists the tasks it created.
Superseding, not editing
AWS’s prescriptive guidance on the ADR process (opens in a new tab) states the rule plainly: once the team accepts an ADR it becomes immutable, and if new insights require a different decision, the team proposes a new ADR; when that one is accepted, the old one’s state changes to Superseded. Fixing a typo is fine. Changing what was decided is a new record.
- Write the new record with the next number, a Supersedes line naming the old one, and a context section that says what changed since.
- Review and accept it the same way as any other.
- Edit exactly one line of the old record: its status becomes “Superseded by ADR NNNN”. Nothing else in it changes.
- Update the index, and the agent instructions if they quote the old decision.
Microsoft’s Azure Well-Architected guidance on ADRs (opens in a new tab) adds a field worth borrowing: record the confidence level of the decision. A choice made on thin evidence, marked as such, is much easier to revisit without a fight.
Keeping ADRs where coding agents read them
An AI coding agent that has not read your ADRs will cheerfully reintroduce the thing ADR 0012 decided against, because the code alone rarely says why it is the way it is. The records need to be in its path, and the fix is two lines in the instruction file the agent loads, AGENTS.md or CLAUDE.md. Examples of those files are in AGENTS.md examples.
## Architecture decisions - Accepted decisions are in docs/decisions/. Read the index, docs/decisions/README.md, before changing structure, dependencies or interfaces, and open any record that covers the area you touch. - Do not contradict an accepted record. If a task seems to need it, stop and draft a new ADR with status Proposed for a person to review.
Point to the index rather than importing every record. Claude Code’s memory documentation (opens in a new tab) says a CLAUDE.md can pull in other files with @path/to/import, and that imported files are loaded into context at launch. Importing a short index is cheap; importing forty ADRs spends context on every session, most of it on decisions the current task never touches. An agent can also draft ADRs well, from a pull request discussion or a design thread, as long as a person reviews the draft and the Deciders line names people.
ADRs, the decision log and rules on fenbs
- An ADR is the full reasoning for one technical decision, kept with the code, read by engineers and coding agents working in that repository.
- A decision log lists every decision a project has made, product and commercial as well as technical, a line or a paragraph each, with ADRs cited by number. The decision log template covers it.
- A rule is a decision that holds from now on and that everyone, and every assistant, should follow without having to find the right file first.
fenbs does not store ADR files; keep them in the repository. What it holds is the other two. On the Decisions and rules page each decision gets its own ref such as DEC-014, with who decided, when, why and the options turned down, and the decider is always a person, never an AI assistant. When an accepted ADR produces an instruction, such as “no new stateful services without an ADR”, record that as a rule there and cite the ADR number in it. Every connected AI assistant reads the rules first, before it touches a task, including assistants working outside the repository the ADR lives in. While an ADR is still proposed, an open decision holds the question, and any task that depends on it shows “decision waiting” on its card. The Consequences line then becomes work: FET-, ENH- and BUG- tasks with the ADR number in the note, linked to the decision.
Related
The project-wide list of decisions: decision log template. Getting to the decision in the first place: decision-making frameworks. Instruction files agents load: AGENTS.md examples and AI context files compared. What every assistant reads before it starts on fenbs: AI context.