HomeBlogOtherWhy Write Architecture Decision Records (ADRs) and When Are They Actually Worth It?

Why Write Architecture Decision Records (ADRs) and When Are They Actually Worth It?

August 7, 2026

Oleksandr Sheiko | Software Developer at SDA

architecture-decision-records

Introduction

The main job of an ADR is to preserve context that disappears faster than code. Write ADRs only for expensive, hard-to-reverse decisions - and keep each one short: context, alternatives considered, and consequences. Everything else is optional.

That's the short answer. The longer story is that most teams get ADRs wrong in one of two directions: they either write nothing and lose years of reasoning, or they document every minor choice until the practice collapses under its own weight. This article is about finding the middle - what to record, what to skip, what a good record looks like, and how to keep the habit alive for years instead of three enthusiastic weeks.

Every developer knows the moment. You open a module, see a strange workaround - a retry loop with oddly specific timeouts, a cache that ignores one particular field, a database query that goes around the ORM - and ask: "why is it like this?" Git blame shows a commit from three years ago titled "fix". The author left the company. Slack history is gone. Nobody knows. And now you face a choice: leave the strange thing alone forever, or remove it and find out the hard way what incident created it.

An ADR exists to make that moment boring instead of dangerous.

What is an Architecture Decision Record?

An Architecture Decision Record (ADR) is a short document - usually one page of markdown living in the repository - that captures a single significant technical decision: what was decided, in what context, which alternatives were considered, and what consequences the team accepted.

The practice was formulated by Michael Nygard in his 2011 blog post "Documenting Architecture Decisions". His core insight: teams don't suffer from missing documentation of what the system does (the code shows that), they suffer from missing documentation of why. Since then the idea has grown a small ecosystem - the most popular template today is MADR (Markdown Any Decision Records), plus tooling like adr-tools and log4brains for managing a log of records.

Key properties that make an ADR different from other documentation:

  • One decision per record. Not "our architecture", but "why we chose PostgreSQL over MongoDB for module X".
  • Immutable history. An ADR is not rewritten when the decision changes. A new ADR supersedes the old one - so the trail of reasoning survives.
  • Lives next to the code. In the repo, versioned in git, reviewed in the same pull requests as everything else.

Why does context disappear faster than code?

Code is stubborn. A function written in 2019 still runs in 2026, character for character. The reasoning behind it has a completely different half-life:

  • People leave. On a typical project, in 2-3 years a large part of the original team rotates out. The reasoning leaves with them.
  • Chats evaporate. The real discussion - "should we go with option A or B?" - happens in Slack threads, calls, and hallway conversations. Six months later even the participants can't reconstruct it.
  • Memory rewrites itself. Even the author, a year later, remembers the decision but not the constraints. "Why did we pick this queue?" - "I think there was some reason..."
  • The context itself changes. The constraint that forced a decision (a library missing a feature, a budget limit, a deadline) may be long gone - but nobody knows the decision is now free to revisit.

The result is a system full of load-bearing mysteries. Teams either fear touching them (velocity drops) or touch them blindly (incidents). Both are expensive, and both are exactly what a one-page record written at decision time would have prevented.

There's a second effect that's easy to underestimate: an ADR helps the author before it helps any reader. Writing "we chose X because..." in full sentences forces you to test your own thinking. About one time in five, the act of listing alternatives honestly reveals that the preferred option doesn't actually survive the comparison - and the decision changes before it ships. That's the cheapest possible moment to catch a mistake.

Which decisions deserve an ADR - and which don't?

The single most important rule of a sustainable ADR practice: write a record only when the future cost of misunderstanding is high. ADRs are for expensive, hard-to-reverse decisions - not for everything.

Decision flowchart for whether a technical decision needs an ADR

Two questions filter most cases:

  1. Is it hard to reverse? Changing a database, a message contract, or a domain boundary means migrations, coordination, and risk. Changing a linting rule means one commit.
  2. Will someone need to understand this later? If a future developer hitting this decision without context could plausibly break something or waste days re-deriving the reasoning - record it.

Decisions that typically deserve an ADR:

  • Choice of database or storage engine
  • Communication style between services (REST vs message queue vs gRPC, sync vs async)
  • Contracts between layers (what the API returns, who owns validation)
  • Caching strategy (what is cached, where, invalidation rules)
  • Domain model boundaries (what belongs to which module, where the seams are)
  • Data routing rules (which requests go where and why)
  • Migration strategy (expand-contract, big bang, dual writes)
  • Choice of a third-party API or critical external dependency
  • Authentication and authorization model
  • Anything that overrides a company-wide default ("we usually do X, here we deliberately do Y")

Decisions that don't:

  • Naming, formatting, code style (that's a linter config, not an ADR)
  • A utility library that can be swapped in an afternoon
  • Implementation details inside one module that don't leak outside it
  • Anything a reader can fully understand from the code and its tests

This filter is not bureaucratic pedantry - it's survival. If the team writes an ADR for every minor choice, two things happen: engineers burn out on documenting instead of building, and the log fills with noise until nobody reads it at all. A practice that produces 4-10 meaningful records a year per team is healthy. A practice that produces four a week is a process problem pretending to be discipline.

What does a good ADR contain?

A good ADR is short - one page, sometimes less. Length is not a sign of seriousness; a decision that needs ten pages to justify usually needs a design doc first and an ADR as its one-page conclusion.

Anatomy of a good ADR and the ADR lifecycle from proposed to superseded

The three sections that carry almost all the value:

1. Context. What was true when the decision was made: the problem, the constraints (technical, budget, deadline, team skills), the forces pulling in different directions. This is the part that evaporates fastest and the part future readers need most. A reader should be able to tell whether the context still holds today.

2. Alternatives. What else was considered and why it lost. This is the section teams skip most often - and the most expensive omission. "We chose RabbitMQ" without alternatives invites the same debate to be re-run every year by whoever recently read a blog post about Kafka. "We considered Kafka, rejected because of operational overhead for a 5-person team; considered Redis Streams, rejected because of missing dead-letter support at the time" closes the debate - or reopens it for the right reason, when a constraint actually changes.

3. Consequences. What the team accepts by choosing this - both good and bad. "We get simple operations; we accept that throughput above N messages/sec will require revisiting this decision." Honest consequences are what make an ADR credible instead of a sales pitch to yourself.

Around those three, a thin frame of metadata:

  • Status - proposed, accepted, deprecated, or superseded (with a link to the successor)
  • Who and when - who proposed, who approved, decision date (one line, not a ceremony)
  • Expectations and success metrics - what should be true if this decision works, and what observation would mean it failed. Example: "success: p95 write latency under 50 ms at 10x current volume; failure signal: cache invalidation bugs appearing in more than one incident per quarter." This single line turns a future argument of opinions into a check against agreed criteria.

A useful template ordering: Title → Status → Date, author, approvers → Context → Decision → Alternatives considered → Consequences → Success / failure signals.

One lifecycle rule worth enforcing: ADRs are never edited into a different decision. When a decision changes, a new record is written and the old one is marked superseded. The chain "ADR-007 superseded by ADR-019" is exactly the history that answers "why is it like this" questions years later.

How do ADRs compare to other ways of keeping knowledge?

Teams already keep knowledge somewhere - the question is how well each place survives time.

Comparison of ADRs in repo versus wiki, code comments, and tribal knowledge

CriterionADR in repoWiki / ConfluenceCode commentsTribal knowledge
Captures the "why"Yes, by designSometimesRarely (usually "what")Yes, until people leave
Survives team rotationYesPartiallyYesNo
Stays near the codeYesNoYesNo
Versioned with the codeYesNoYesNo
Records alternativesYes, by designRarelyAlmost neverFades in months
Findable when neededHigh (one folder, numbered)Low (search across stale pages)Low (must know where to look)Depends on who's online
Rots silentlySlowly (status field)FastMediumFastest
Cost to maintainLow (write once)High (needs gardening)LowZero until the bill arrives

These aren't competitors so much as different tools: comments explain a line, wikis explain how to run things, ADRs explain why the system is shaped the way it is. The failure mode is trying to make one of the first two do the third's job.

Business perspective: what does lost context cost?

ADRs look like a purely engineering habit, but the costs they prevent land squarely on the business side. The trap is that decision context is a known cost to preserve and an invisible cost to lose - nobody gets a monthly invoice for "re-derived reasoning", so it feels free right up until it isn't.

Where the money actually goes:

1. Onboarding. A new developer in a codebase without decision history spends weeks reverse-engineering intent - reading code tells them what it does, not whether it's intentional. Reading a folder of 20 ADRs takes an afternoon and answers the top layer of "why" questions at once. On teams we've worked with, decision records plus module docs were a major factor in cutting time-to-first-meaningful-task from about a month to 1-2 weeks.

2. Re-litigated decisions. Without a record, big choices get re-debated every time the team composition changes. Each round costs meeting hours of the most senior (most expensive) people - and produces either the same conclusion (pure waste) or a different one made without the original constraints (risk).

3. Incidents from undone decisions. The most expensive failure mode: someone removes a "weird" workaround that was actually load-bearing, because nothing explained why it existed. The cost isn't the fix - it's the production incident, the customer impact, and the week of firefighting. Read more about how unmanaged technical debt compounds into exactly this kind of risk.

4. Bus factor. When reasoning lives in two heads, those two people can't take vacations during critical periods, can't be promoted away from the module, and their resignation is a small crisis. That's an operational risk with a real price, and it's exactly what written decision history dissolves.

How to explain the practice to stakeholders: don't sell "documentation" - nobody funds documentation. Frame it as risk insurance with a known premium: roughly 1-2 hours of engineering time per significant decision, against onboarding measured in weeks, senior hours burned on repeated debates, and incident risk from blind changes. At 4-10 records a year, the annual premium is a rounding error.

Case study: introducing ADRs on an inherited codebase

The same project we described previously: a property and building management platform for the Danish market. React on the frontend, Python (Django REST) and PostgreSQL on the backend, integrations with external government APIs. Team of five: 2 backend, 2 frontend, 1 fullstack.

Starting state, relevant to this story:

  • The codebase was inherited from a previous team; documentation was almost nonexistent
  • Knowledge of "why exactly this way" was lost - the original authors were unreachable
  • Several modules contained non-obvious logic around external API integrations that nobody dared touch
  • Every significant technical discussion happened in calls and chat, leaving no durable trace

When we committed to module-by-module refactoring, we added a rule: every significant decision made during the work gets an ADR in MADR format, in the repo, reviewed in the same pull request as the change. Not for everything - only where the two-question filter (hard to reverse? will someone need this later?) said yes.

What we did specifically:

  • Created a single docs/adr/ folder with numbered markdown files and a short template: context, decision, alternatives, consequences, status, success signals
  • Wrote ADRs for the decisions that actually cleared the bar: switching an integration from proxy-streaming files through Django to short-lived signed URLs from object storage; the strategy for a major PostgreSQL version upgrade; caching rules for slow external government API responses; contracts between frontend forms and backend validation
  • Explicitly did not write ADRs for module-internal refactoring choices, library swaps, or style decisions - those went into normal PR descriptions
  • Marked one early record superseded within three months when a constraint changed - and treated that as the system working, not failing

Results after about six months:

  • The ADR log contained 14 records - small enough that a new developer read all of them in one sitting during onboarding
  • Onboarding time to first meaningful shipped task dropped from roughly a month to 1-2 weeks (ADRs plus module docs together)
  • Two planned changes were redesigned at the writing stage - listing alternatives honestly showed the first idea didn't survive comparison, before any code was written
  • Zero incidents of the "removed a workaround nobody understood" type in refactored modules - the workarounds now had recorded reasons, so they were either kept knowingly or removed safely
  • Technical debates stopped restarting from zero: twice, a "why don't we just use X" discussion was resolved in minutes by linking the existing record

The main takeaway: the value didn't come from writing a lot. It came from writing little, at the right moments, in a place where the next person would trip over it. Fourteen short pages replaced the two departed engineers' worth of context we never had.

Common mistakes with ADRs

1. Writing an ADR for everything. The fastest way to kill the practice. Documenting every minor choice burns the team out and buries the few important records under noise. Use the filter: high cost of future misunderstanding, hard to reverse.

2. Writing the record months after the decision. By then the context is already half gone and the alternatives are misremembered. An ADR is written when the decision is made - ideally in the same pull request.

3. Skipping the alternatives section. "We chose X" without "instead of Y and Z, because" answers nothing. Alternatives are what prevent the same debate from being re-run annually.

4. Writing novels. Ten pages is a design document, not an ADR. If it doesn't fit on roughly one page, the decision isn't distilled yet.

5. Recording only the upside. An ADR with no downsides in Consequences is a sales pitch, not a record. Future readers trust records that admit what was traded away.

6. Editing old ADRs instead of superseding them. Rewriting history destroys the trail that makes the log valuable. New decision - new record, old one marked superseded with a link.

7. Storing ADRs outside the repository. A decision log in a wiki nobody opens is a decision log that doesn't exist. Records live next to the code they explain and go through the same review flow.

8. No success or failure criteria. Without "what would tell us this worked or failed", revisiting the decision later becomes an argument of opinions instead of a check against agreed signals.

Conclusion

An ADR practice succeeds on restraint, not volume. The point was never to document the system - it's to leave a short, honest trail behind the handful of decisions that will be expensive to misunderstand later.

A working setup checklist:

  • Records live in the repo (docs/adr/), reviewed in pull requests
  • One page per decision: context, decision, alternatives, consequences
  • One line of metadata: status, date, author, approvers, success/failure signals
  • The two-question filter applied before writing: hard to reverse? needed later?
  • Decisions change by superseding records, never by editing them
  • New developers read the full log during onboarding - and it's short enough that they actually can

The long-term payoff is quiet. Nothing dramatic happens - which is exactly the point. Questions that used to start archaeology sessions get answered by a link. Workarounds stop being landmines. Debates don't restart from zero when the team changes. The system stays understandable not because the code explains itself, but because someone spent an hour, at the right moment, writing down why.

FAQ

What is an ADR in software development?

An Architecture Decision Record is a short document, usually one markdown page in the repository, that captures one significant technical decision: the context, the decision itself, the alternatives considered, and the consequences accepted.

When did ADRs originate?

The practice was formulated by Michael Nygard in his 2011 blog post "Documenting Architecture Decisions". The MADR template and tools like adr-tools and log4brains grew out of that idea later.

ADR vs design doc vs RFC - what's the difference?

A design doc explores a problem and proposes a solution before the decision; an RFC collects feedback on a proposal; an ADR records the final decision and its reasoning after it's made. On big decisions they chain naturally: RFC or design doc first, ADR as the one-page outcome.

How long should an ADR be?

About one page. Context, decision, alternatives, consequences, plus a line of metadata (status, date, author, success signals). If it needs ten pages, write a design doc and let the ADR summarize its conclusion.

Where should ADRs be stored?

In the repository, next to the code - typically a docs/adr/ folder with numbered markdown files, reviewed in pull requests like any other change. Wikis are where decision logs go to be forgotten.

Do small teams need ADRs?

Yes - arguably more. Small teams have the worst bus factor: one departure can erase half the system's reasoning. The cost is tiny at small scale: a handful of records a year.

What happens when a recorded decision changes?

Write a new ADR and mark the old one superseded with a link to the successor. The old record is never edited into a different decision - the chain of superseded records is the history that answers "why" questions years later.

How many ADRs should a team produce?

There's no quota, but a healthy signal for a single product team is roughly 4-10 meaningful records a year. Several per week means the filter is broken and the practice is heading for burnout.

SHARE YOURIDEASTO MAKE THEMREAL

Feel free to reach out if you want to collaborate with us, or simply have a chat.

Don't like the forms? Drop us a line via email.

contact@sda.company

...or give us a call. 🇺🇸 +1 929 322 8837 🇬🇧 +44 7700 183718