Using Architecture Decision Records (ADRs) to Prevent Chaos

Felipe Hlibco

Last month I watched two senior engineers spend an entire sprint debating whether to use GraphQL or REST for a new internal API. They eventually chose GraphQL. The thing is, we’d already made that decision eight months ago for a different service — with reasoning that lived nowhere except maybe in Dave’s head. (Dave left in March.)

This happens constantly. A decision gets made in a meeting, or a Slack thread, or occasionally in someone’s head while they’re showering. Then people leave, context evaporates, and the next team walks into the same intersection and argues from scratch. Same debate, same circular reasoning, same outcome — or worse, a different one.

Architecture Decision Records fix this. They’re simple, they live in your repo, and they cost almost nothing beyond the ten minutes it takes to write one.

What an ADR actually looks like #

Michael Nygard proposed the format back in 2011, and it’s held up well because it’s minimal — almost aggressively so. An ADR is a short markdown file with three sections:

Context. What’s the situation? What constraints exist? What are we actually trying to solve?

Decision. What did we decide? State it clearly. No hedging.

Consequences. What follows from this decision? Both good and bad. What trade-offs did we accept?

That’s it. No templates with fourteen fields, no approval workflows, no JIRA tickets. Just a markdown file in a docs/adr/ directory, numbered sequentially: 001-use-graphql-for-internal-apis.md.

The format forces a specific kind of clarity. Writing down consequences means you have to actually think about trade-offs before committing. I’ve watched teams change their minds mid-ADR because the consequences section made the downsides too visible to ignore. That’s not a failure of the process — that’s the process working exactly as intended.

The real problem ADRs solve #

It’s not documentation. Documentation is a side effect, and honestly, a boring one.

The actual problem is decision drift. Teams make architectural choices based on context that’s invisible to anyone who wasn’t in the room. Six months later, a new engineer joins. They see a pattern they don’t understand, assume it’s accidental or legacy, and start building something contradictory. Nobody catches it because the original context was never written down — it lived in Slack, and Slack deletes messages after 90 days.

ADRs create what Spotify’s engineering blog called a “decision log” — a chronological trail of why the system looks the way it does. When someone asks “why are we using Redis for this instead of Postgres?” the answer isn’t “ask Dave” (again: Dave left). The answer is ADR-014. Go read it.

This matters even more on distributed teams. At TaskRabbit we’ve got engineers in four time zones. Synchronous decision-making doesn’t scale when half the team is asleep during the other half’s working hours. An ADR in a pull request works asynchronously — people review it, comment, and the merge itself constitutes agreement. No meeting required.

Making ADRs stick #

The pattern fails when it becomes bureaucratic. I’ve seen teams require ADRs for everything, including trivial choices like which linting rule to enable. That kills adoption fast. People start writing them to check a box, which means they stop writing them thoughtfully.

My rule of thumb: write an ADR when a decision would be hard to reverse, or when you expect someone to question it later. Database choices, API contract changes, authentication patterns, state management approaches — these deserve ADRs. Which npm package to use for date formatting probably doesn’t. Trust your judgment; you’re an engineer, not a bureaucrat.

The other adoption killer is putting ADRs somewhere nobody looks. A Confluence page buried three folders deep is effectively invisible. ADRs belong in the repository they affect, in a predictable location. docs/adr/ or docs/decisions/. Version-controlled, searchable, and visible in the same PR workflow engineers already use.

Joel Parker Henderson maintains a solid collection of ADR templates and examples on GitHub if you want a starting point. But honestly? Nygard’s original three-section format is all you need. Start there. Add structure later if you outgrow it — though most teams never do.

The onboarding multiplier #

Here’s an underappreciated benefit, one I didn’t expect when we started using ADRs at TaskRabbit. When a new engineer joins your team, they can read through the ADR log chronologically and build a mental model of how the system evolved. Not just what the architecture is, but why it looks this way — what alternatives were considered, what constraints existed, what was tried and abandoned.

That context transfer used to take weeks of shadowing and asking questions. ADRs compress it into a few hours of reading. It’s not a replacement for mentorship — you still need humans — but it eliminates the most repetitive part of onboarding: answering “why did we do it this way?” for the fifteenth time.

If your team doesn’t use ADRs yet, start with the next decision that generates debate. Write it up. Three sections, ten minutes, maybe fifteen if you’re being thorough. You’ll reference it sooner than you think.