An architecture decision record (ADR) is a short document, usually a numbered markdown file stored next to the code, that captures one significant technical decision along with the context that forced it, the options considered, the option chosen, and the consequences expected. That is the whole idea behind how to document decisions in a technical team: you write down the reasoning while it is still fresh, not a description of the code after it exists.
Every useful decision record has four sections, in this order:
- Context — the problem, the constraints, and what made the decision necessary now.
- Decision — what you chose, in one sentence someone can quote.
- Alternatives considered — what else was on the table and why each one lost, including doing nothing.
- Consequences — what becomes easier, what becomes harder, and what would reopen this decision.
Michael Fowler’s write-up on architecture decision records is still the cleanest one-paragraph definition, and the ADR GitHub organization keeps the community templates in the Nygard and MADR formats. Copying either of those is fine. What competitors tend to skip is the part that decides whether the practice survives: who decides, how long the review window runs, and what happens to the record two years later when the code underneath it has moved on.
So the record is maybe twenty percent of the job. The other eighty percent is knowing which choices deserve one, having a named decider instead of a room full of nodding, and superseding old records rather than quietly editing them. This guide covers the format and the process around it, with a worked example from a city open-data stack, because that is the kind of project where the memory of a single engineer is the single point of failure.
Table of Contents
- What You Need to Document Decisions in a Technical Team
- A shared place records live in
- One format, not five
- A named decider
- The context that makes it readable later
- A review path
- Know which decisions deserve a record at all
- Pick the right kind of document
- Decide where records live before you write the first one
- Step-by-Step
- Step 1: Identify a Decision Worth Recording
- Step 2: Gather the Context and Constraints
- Step 3: Compare the Real Alternatives
- Step 4: Record the Decision and Its Reasoning
- Step 5: Review, Publish, and Link the Record
- Step 6: Connect the Decision to Delivery Work
- Step 7: Review Decisions When Context Changes
- Common Mistakes
- Recording the outcome without the reasoning
- Writing for the moment instead of for the reader later
- Using vague status labels
- Documenting every trivial choice
- Leaving ownership vague
- Never superseding an old record
- Keeping records where the work does not happen
- Frequently Asked Questions
- What is an architecture decision record?
- What is the difference between a design doc and an ADR?
- Who approves an ADR?
- How long should an ADR be?
- How do you keep decision records from going stale?
- Do ADRs replace other engineering documentation?
- Conclusion
What You Need to Document Decisions in a Technical Team
Five things have to exist before anyone writes a record, and none of them are software. Teams that skip this part end up with a docs folder full of files nobody reads, which is worse than nothing because it looks like documentation and is not.
A shared place records live in
The place has to be somewhere the whole team already opens. For most engineering teams that means a folder in the git repository, usually docs/decisions/ or docs/adr/, because the record then travels with a checkout, gets code review, and shows up in the diff when the decision changes. A wiki page works when the people who make the decision are not the people who write the code.
One format, not five
Pick a single template and keep it. The temptation is to invent a new shape for each hard decision, and by the fourth shape nobody can skim it. Two formats are usually enough: a short record for ordinary decisions and a longer proposal for the ones that still need arguing.
A named decider
Write down who makes the call before you start arguing. In practice most technical decisions have one decider (the tech lead or staff engineer) and several contributors, and the record should say which is which. Teams that skip this end up with a decision that reopens a week later because the person who dissented was never asked.
The context that makes it readable later
The reader six months from now will not remember the thread, the meeting, or the deadline. They will have the record. So you need enough context written down that a stranger can follow the reasoning without asking anyone, and that means capturing the constraints you were operating under, not just the options you weighed.
A review path
Somewhere for comments, a window to leave them, and a rule for closing. Without a closing rule, records sit in draft for a month and quietly stop meaning anything.
Know which decisions deserve a record at all
Here is where most teams over-document and then resent it. Sort decisions by two things: how reversible the choice is, and how far the blast radius reaches when it is wrong.
| Decision class | Example | What it deserves |
|---|---|---|
| Local and reversible | Which test helper to use, folder layout inside one module | A line in the commit message or a comment in the pull request |
| Cross-feature, reversible | Choosing a state management library for one app | A short record, five minutes to write |
| Persisted data or a public API | Schema shape, endpoint contract, event format | A full record plus a migration and rollback plan |
| Cross-team boundary | Which service owns identity, who holds the data authority | A full record with decision rights, open to the affected teams |
| Hard to reverse or expensive to unwind | Vendor lock-in, a framework that shapes everything, a storage engine choice | A full record with a proof of concept, and revisit triggers that name evidence |
People on r/ExperiencedDevs describe roughly this habit in practice: they record architectural decisions when the choice crosses team boundaries, not everything. That instinct is right. A record for a reversible local choice costs more to maintain than it ever saves.
Pick the right kind of document
Design docs, RFCs, ADRs and decision logs get confused for each other, and the confusion wastes time because each one has a different job.
| Document | What it is for | When it is written | Typical length | Who reads it |
|---|---|---|---|---|
| Decision log | A running list of what was decided and when | Continuously, after decisions happen | A few lines per entry | Newcomers scanning for context |
| Architecture decision record | One decision plus its reasoning and consequences | At the moment of the decision | One page | Engineers who will change that part of the system |
| Technical design doc | Exploring and proposing a solution in detail | Before the decision is made | Several pages | Reviewers of the proposal itself |
| RFC (request for comments) | Gathering objections before committing | Before the decision is made, open window | Two to five pages | Everyone affected, invited to object |
The short version practitioners repeat is worth keeping: a design doc explores and proposes, an RFC gathers objections, an ADR records the decision. Pick by consequence, not by habit. Running all four in sequence for every choice is how documentation practices die.
Decide where records live before you write the first one
Repository markdown wins on version history and search, and it is the only option that works well with code review. A wiki or knowledge base wins when the decision-makers are outside engineering or when non-engineers need to read the reasoning. A Slack thread is not a system of record, whatever anyone says about searchable history; decisions that live only in a channel are gone when someone leaves the company.
For teams with no repository culture yet, start with numbered files in the repo anyway. 0001-use-postgis-for-geocoding.md sorts chronologically, never gets rewritten, and gives you a diff on every future change.
Step-by-Step
Below is the process I would hand a team starting on their first record. It takes about thirty minutes for a normal decision, not a week, and the order matters more than the length.
Step 1: Identify a Decision Worth Recording
Most questions about how to document decisions in a technical team come down to this: what counts as a decision worth the effort? Use a trigger rather than a vibe. Write a record when a choice meets any one of these.
- It is expensive or awkward to reverse.
- It changes something other teams depend on, including a schema, an endpoint, an event, or a shared permission model.
- It commits the team to a vendor, a platform, or a data authority for more than one release cycle.
- It sets a security or privacy boundary.
- You can already picture the same argument happening again next quarter.
That last one is the most useful signal, because it is the cost you are actually paying. If two people have already disagreed about this twice, the disagreement is not going to resolve itself by being louder next time.
Skip the record when the choice is a local implementation detail, when the code makes the reasoning self-evident, or when the decision has already been made and shipped and nobody can remember why. Reverse-engineering a rationale for a choice you no longer remember almost always produces fiction, and fiction in a decision record is worse than a gap.
Step 2: Gather the Context and Constraints
Write the problem before you write the answer, and write it so that someone who was not in the room understands why this came up. Three to five sentences is usually right. Include the deadline or trigger if there is one, because a decision that had to happen before a demo is a different decision from the same choice made calmly.
Then list the constraints that actually bound the solution. Rank them, because an unranked list hides which requirement you were willing to trade away. A useful pattern is goals and non-goals: what this decision must achieve, and what it deliberately does not attempt.
Add the stakeholders affected, and be specific. On a city open-data project that usually means the data team, the internal analytics group, the publishing partner, and whoever handles accessibility review. “The team” is not a stakeholder list.
Finally, attach the evidence you leaned on: a load test, a benchmark, a support ticket, an accessibility audit, a schema comparison, a short proof of concept. Evidence is what makes a revisit trigger real later. Without it, a record can only be reopened by someone feeling uncomfortable, which is not a process.
Step 3: Compare the Real Alternatives
List the credible options, and always include the status quo as one of them. Doing nothing is a choice with consequences, and it wins more often than teams expect. If your record has two options and one of them is the thing you already have, you have not finished thinking.
Give each option the same treatment so the comparison is honest: what it costs to build, what it costs to maintain, what it does to your delivery date, and what it does to the next engineer who inherits it. Keep it to a short table or a few bullets per option.
Do not stage a straw man. A rejected option that is obviously bad makes the whole record look like a justification rather than a decision, and reviewers spot that instantly. If an option was seriously considered, say what would have made it win.
Record the dissent too. If two engineers disagreed and lost, that disagreement is useful context for the next person who reads the record and thinks the choice is wrong. One line naming the objection and why it was not followed is enough.
Step 4: Record the Decision and Its Reasoning
Now write the file. Keep the four sections, add a small header with the decision rights and status, and stop. A one-page record that a reviewer understands in ten minutes is the target; longer means the decision was probably two decisions.
The status field should use a fixed vocabulary so nobody has to guess: proposed, accepted, rejected, superseded by ADR-NNNN. Vague labels like approved-ish or done are the thing that turns a records folder into noise.
The decision rights header names the roles, so approval is never a mystery: the proposer, the decider, the payer (who funds the work), the executor (who builds it), and the reopener (who is allowed to challenge it later). This is the single highest-value line in the whole record, and it is the piece most teams skip.
Add revisit triggers that name evidence rather than feelings. “If ingestion falls behind by more than an hour at peak” is a trigger. “If we find a better option” is not, because nobody can ever settle whether they have found one.
Here is a copy-paste template. Save it once, strip the guidance comments, and reuse it.
# ADR-NNNN: Short title stating the decision in one line
- Status: proposed | accepted | rejected | superseded by ADR-NNNN
- Date: YYYY-MM-DD
- Proposer:
- Decider:
- Payer:
- Executor:
- Reopener:
- Affects: services, teams, or contracts this touches
## Context
What problem exists, what constraints apply, and why a decision is
needed now. Three to five sentences. Rank the constraints if more
than one competes.
## Decision
One sentence. "We will X." The rest of the document explains why.
## Alternatives considered
### Option A: name
- Build cost:
- Ongoing cost:
- Effect on delivery date:
- Why not chosen:
### Option B: do nothing
- Why not chosen:
## Consequences
### Good
-
### Bad
-
### Revisit triggers
- Trigger 1: named evidence that would cause this to reopen
- Trigger 2:
## Dissent
One line per objection, with the reason it was not followed.
## Links
- Design doc, RFC, proof of concept, benchmark, pull request
That template is the MADR shape trimmed to what a small team will actually finish. The community templates at adr.github.io are worth reading once if you want more options, including the Nygard format that treats the record as context, decision and consequences only.
On length: if it runs past two pages, you have probably written a design doc and labelled it a record. Split it. The proposal and the arguments belong in a design doc, and the ADR links to it and states what was chosen.
Step 5: Review, Publish, and Link the Record
Open the record as a pull request, not as a broadcast message. That way comments live with the file, the history is in the repo, and the record gets the same review discipline as code.
Set a comment window based on how many teams are affected: two working days for a single team, five for anything cross-team or contract-affecting. Say the date in the pull request so nobody has to guess when silence becomes approval.
Then state the rule for what happens when nobody objects, because this is the question every forum thread on this topic asks and almost nobody answers. Silence after the window is acceptance by the decider. Not consensus, not a vote, just a named person closing it. On r/ExperiencedDevs, senior engineers push back hard on consensus theatre for exactly this reason: a room full of nodding feels like agreement and produces no accountable owner.
Resolve comments in the thread so the reasoning stays visible, then flip the status to accepted and merge. If a comment changes the decision in any material way, update the record before merging rather than after.
Where it gets published matters as much as when. The repository is the archive; the team channel is the announcement. Post a two-line summary with a link, so people learn the decision exists without learning it from the file.
Step 6: Connect the Decision to Delivery Work
A record that is disconnected from the work will not be read. Link it in both directions.
- Reference the record number in the implementation ticket and in the pull request that lands the change.
- Link the record from the README of the service it governs, so someone reading the code finds the reasoning at the point of confusion.
- Link the design doc or RFC the decision came out of, and link forward to the follow-up tickets it generated.
- Add the owning team to a codeowners file if the decision created a new boundary, so reviewers for that area are the people who were consulted.
There is one more connection worth making right now, because more teams are asking about it. Coding assistants do not read your Slack history or guess what the team convention is; they read files in the repository and the instruction files at the root. If a decision like “all geospatial queries go through PostGIS, never client-side bounding boxes” lives only in an ADR that no one has pointed an agent at, the assistant will keep writing code that violates it.
The fix is small. Keep a short root-level instruction file, named for the assistant your team uses, and state the handful of decisions that an agent must follow, each with a link to the full record. Keep it to the rules that would otherwise be broken repeatedly. Several threads on r/ClaudeCode and r/AI_Agents in the past year describe the same failure: an agent that ignored architectural conventions nobody had written down in a machine-readable place.
Step 7: Review Decisions When Context Changes
Records rot because the system moves and the file does not. The fix is to make review a scheduled, boring event rather than something that depends on someone caring.
Give each record revisit triggers, as above, and treat them as a checklist item in planning. When a trigger fires, do not argue from memory. Gather the new evidence, and write a new record that supersedes the old one.
Superseding, never editing. A superseded record keeps its text and gets a status line pointing at the new number. This is the discipline most teams skip, and it is the one that makes the archive trustworthy: if record 0007 says we chose Postgres and record 0021 says we moved to something else a year later, a new engineer can follow the story instead of finding a confidently wrong document.
Two more maintenance habits pay for themselves. Audit the folder once a quarter for records with no linked implementation and no recent activity; they are either noise or a decision that quietly never happened. And reassign ownership when the author leaves, because a record with a name that no longer appears in the team directory is one fewer person who can explain it.
One warning about precedent. Teams copy old records into new work, and the copied decision carries assumptions that were true two years ago and are not true now. A short line in every record stating what it assumed about scale, team size, or regulatory context makes the copy-paste habit survivable.
Common Mistakes
Each of these kills the practice faster than not starting at all.
Recording the outcome without the reasoning
A record that says we chose Postgres and nothing else is a lie of omission; the interesting part is always why. Fix: make the Context section mandatory. If you cannot write the context, you do not understand the decision well enough to record it.
Writing for the moment instead of for the reader later
Records written as status updates to people who were in the conversation leave out every assumption. The reader six months from now is a stranger. Fix: write for that stranger and include the constraints you were operating under.
Using vague status labels
Approved-ish, discussed, maybe revisit. Fix: a closed vocabulary of proposed, accepted, rejected, and superseded, with the superseding record number included.
Documenting every trivial choice
When the records folder fills with library choices, nobody reads any of them. Fix: the reversibility and blast radius filter from earlier. Permission to skip documentation for small decisions is what makes the important ones worth reading.
Leaving ownership vague
If the record does not say who decided, the decision is not actually closed. Fix: proposer, decider, payer, executor, and reopener in the header. Four lines.
Never superseding an old record
The archive quietly turns into fiction, and people start distrusting the folder entirely. Fix: new record, status line on the old one, never a retroactive edit.
Keeping records where the work does not happen
A perfect record in a wiki nobody opens is a lost record. Fix: store it next to the code, link it from the service README, and announce it once in the team channel.
Two habits make the rest easier. Start with the highest-impact decisions only, so the first month produces three records that are actually useful rather than thirty that are ignored. And time-box the effort honestly: thirty minutes for a normal decision, half a day for the irreversible ones with a proof of concept. Anyone promising you a week of process per decision has never had to ship anything.
Frequently Asked Questions
What is an architecture decision record?
An architecture decision record is a short document, usually a numbered markdown file stored next to the code, that captures one significant technical decision with the context that forced it, the options considered, the option chosen, and the expected consequences. It records reasoning rather than describing code, and it is versioned like source code so the history of choices stays readable.
What is the difference between a design doc and an ADR?
A design doc explores and proposes a solution, so it is written before the decision and is usually long enough to argue about. An ADR records a decision that has already been made, in about a page, and is never rewritten. An RFC sits between them: it exists to gather objections before anyone commits. Pick by consequence rather than by habit.
Who approves an ADR?
One named decider approves it, usually the tech lead or staff engineer, and the record says so in the header along with the proposer, the payer, the executor, and the person allowed to reopen it. Contributors comment during a stated window. When the window closes without a blocking objection, the decider accepts it. Consensus is not an approval process.
How long should an ADR be?
About one page, and a reviewer should be able to understand the decision in ten minutes without scrolling back. If yours runs longer, it is probably a design doc that should be linked rather than inlined. Two pages is the practical ceiling for a record, since anything larger stops being read at the moment someone needs the answer.
How do you keep decision records from going stale?
Give every record revisit triggers that name evidence, not discomfort, and check them during planning. When a trigger fires, write a new record that supersedes the old one instead of editing it, and leave a status line pointing at the new number. A short quarterly audit of records with no linked implementation catches the ones that quietly never happened.
Do ADRs replace other engineering documentation?
No. ADRs cover decisions and their reasoning. Runbooks cover operating the system, postmortems cover incidents, design docs cover proposals, and README files cover how to get started. Teams that try to make one artifact do all five jobs end up with long records nobody reads. When you are learning how to document decisions in a technical team, treat the record as one tool with one job.
Conclusion
Pick one decision your team is about to make this month, the kind that crosses a service boundary or commits you to something awkward to unwind. Write the one-page record using the template above, name a decider, open it as a pull request with a two-day comment window, and merge it into docs/decisions/ with the next number in sequence.
Then do it three more times and stop. Four records a quarter is a habit; forty is a documentation backlog nobody asked for. The teams that get value from this are not the ones that document everything, they are the ones that record the expensive choices once and let the small ones go undocumented.


