Architecture decision records: write down why, not only what
A short, practical guide to architecture decision records: what to put in one, when to write it, and how a decision log saves your team repeated debates.

Six months after a project starts, someone asks a fair question: "Why do we use this queue and not that one?" The people who chose it may have left, or they remember a bit of the story but not the constraints. The code shows what the system does. It almost never shows why it was built that way, and without the why, the same debate returns every year.
An architecture decision record, or ADR, is a small answer to that problem. It is one short document about one decision.
What an ADR is
The ADR community site describes an architectural decision as a justified design choice that addresses an architecturally significant requirement. An ADR "captures a single AD and its rationale", so readers can see the reasons, trade-offs and consequences. All the records of a project together form its decision log.
The format was popularised by Michael Nygard's 2011 blog post, and the site's template page lists the sections of his version: title, status, context, decision and consequences. That is about as light as documentation gets, and the lightness is the point. A record that takes twenty minutes to write actually gets written.
A template you can copy
Here is a minimal version, in Markdown, that follows those five sections:
# 12. Use a Postgres-backed job queue
Status: Accepted (2026-11-04)
## Context
We need background jobs for email and report generation. Volume is
low (a few thousand a day). We already run Postgres and have no
one on call for another system.
## Decision
We will use a job queue that stores jobs in our existing Postgres
database.
## Consequences
- One less service to run, back up and monitor.
- Jobs can be enqueued in the same transaction as the data change.
- Throughput is limited by the database; revisit above ~100 jobs/second.
- Moving to a dedicated broker later means rewriting the enqueue calls.
Notice what the example does. The context lists facts and constraints, not opinions. The consequences list good and bad outcomes. It even says when to revisit the choice. That is more useful than a decision alone.
Write about decisions that are hard to undo
Not every choice deserves a record. A good test: would a new engineer, a year from now, be surprised or ask why? And would reversing the decision be expensive?
Good candidates:
- Choice of database, queue, framework or hosting model
- How services talk to each other, and how they authenticate
- Data ownership and tenancy rules
- A deliberate non-choice, such as "we are not splitting this into services yet"
- A trade-off with a cost you accept knowingly, like eventual consistency
Poor candidates are formatting rules, variable names and anything a linter can enforce. Those belong in a style guide.
Decisions about how much autonomy to give software are worth recording too. If your team picked a fixed pipeline over a free-running agent, a record can capture the reasoning that our post on choosing between a workflow and an agent walks through.
Capture the options you did not pick
The most valuable part of an ADR is often the paragraph about alternatives. Fuller templates, such as MADR, include a section for considered options with the pros and cons of each, as well as metadata like who decided. You can add it to the small template above:
## Options considered
- Dedicated message broker: more throughput, but a new system to operate.
- Cron plus a table: simple, but no retries or visibility.
- Postgres-backed queue: chosen.
Future readers rarely ask "what did you choose?" because the code answers that. They ask "did you think about X?" Having X on the page, with the reason it lost, ends that conversation in a minute.
Keep them small, dated and immutable
A few habits make a decision log stay healthy:
- One decision per record. If you want to write "and also", write two.
- Store them in the repository, next to the code, numbered in order, for example
docs/adr/0012-postgres-job-queue.md. They then go through review like code and move with the branch. - Give each a status: proposed, accepted, or superseded. Statuses are the part of the template that keeps a log honest.
- Do not rewrite history. When circumstances change, write a new record that replaces the old one, and mark the old one as superseded with a link. The trail of reasoning is itself the value.
- Date every record. "We chose this in 2026 under these constraints" reads very differently from an undated statement.
Use the record as a review tool
An ADR is easier to argue with than a chat thread. Open a pull request with a proposed record, and let colleagues comment on the context and options. People can disagree with a fact in the context ("actually volume is ten times that") before anyone has to disagree with a person. When the pull request merges, the decision, the debate and the date are all in version control.
It also helps with changes that need care for safety, such as retry behaviour. A record that states "all write endpoints accept idempotency keys" turns a good intention into something the team can point to and check new work against.
Common ways it goes wrong
- Records that are too long. If it takes an afternoon, nobody will write the next one.
- Writing it after the fact, with only the winning argument remembered. Write while the options are still open.
- A folder nobody links to. Mention the relevant record in pull request descriptions and in onboarding notes.
- Treating it as permission. An ADR documents a decision, it does not make a decision right. Revisit when the context changes.
Start with one
You do not need a process rollout. Take the most recent decision someone on your team had to explain twice. Write it in the five-section template above, add a short list of options, and put it in the repository. If it saves a single meeting, the next one will be easier to justify.


