Every codebase I've inherited has had a few decisions that made no sense. Why is this service on a different database from everything else? Why do we serialise these events by hand? Why is there a queue here at all? Usually there was a good reason once. Nobody remembered it, so the team either left things alone out of fear or changed them and rediscovered the original problem the hard way.
Architecture decision records, or ADRs, are the fix. They're short documents that capture one significant decision, its context and its consequences, written at the time the decision is made. They're the cheapest habit I know of with the biggest long-term payoff, and they take about half an hour each.
What an ADR is (and isn't)
An ADR is a record of one decision. Not a design doc, not a specification, not a wiki page that tries to describe the whole system. It answers four questions:
- What was the situation? The forces at play, the constraints, the problem we needed to solve.
- What did we decide? In one or two clear sentences.
- What else did we consider? And why we didn't choose it.
- What are the consequences? Including the bad ones we're accepting.
The format matters less than the habit. I've seen teams succeed with markdown files in the repo, with pages in a wiki and with entries in a shared document. The one thing they all had in common: the records were easy to find from where the code lives.
The template I use
I keep it short on purpose. A long template is a template nobody fills in.
# 0012. Use PostgreSQL for the order service
Status: Accepted
Date: 2026-03-04
Deciders: Order team, platform architect
## Context
Orders need multi-row transactions across order lines, payments and stock
reservations. The team runs PostgreSQL in production already. Expected volume
is under 500 writes per second for the next two years.
## Decision
We will store orders in PostgreSQL, in a schema owned by the order service.
## Alternatives considered
- DynamoDB: scales further, but cross-item transactions are limited and
the team has no operating experience with it.
- The shared reporting database: rejected, it couples us to other teams' schemas.
## Consequences
- Simple transactions and a familiar stack.
- We will need read replicas or a separate store if reporting load grows.
- Revisit if sustained writes exceed 2,000 per second.Notice the last line. A good ADR often says when it should be revisited. That turns "we're stuck with this" into "we agreed in advance what would make us change our minds".
When to write one
Not every decision deserves an ADR. If you write one for every library upgrade, people stop reading them. The test I use is simple: would a capable engineer joining in a year be confused, or tempted to undo it, without knowing why?
Decisions that usually pass the test:
- Choosing a database, message broker or other core infrastructure.
- Drawing or moving a boundary, such as splitting a module or extracting a service.
- Choosing an integration style, for example events versus synchronous calls between two systems.
- Accepting a known trade-off, like eventual consistency in one area, or skipping a cache for now.
- Deciding not to do something that seems obvious, such as not adopting the company-standard framework for good reasons.
That last category is underrated. The decisions that most often get relitigated are the ones where the team chose the unexpected option.
The most expensive decisions in software are the ones that get made twice because nobody wrote down the first one.
Keeping them alive
ADRs fail when they become a ritual that nobody reads. A few practices keep them useful.
Store them next to the code
A docs/decisions folder in the repository works well. ADRs then go through the same pull-request review as code, they're versioned with the system they describe, and they show up when someone searches the repo.
Never edit an accepted decision; supersede it
When a decision changes, write a new ADR that references the old one, and mark the old one "Superseded by 0031". The history is the point. Someone reading in three years can follow the chain and see how the thinking evolved, and why.
Review them where decisions are made
If your team has a weekly architecture or design review, end each significant discussion with "who's writing the ADR?" Assign a name and a date. A decision without a record tends to drift in people's memories within weeks.
Link them from where people will look
Reference the ADR in the code comment above the surprising thing, in the README for the service, and in the onboarding guide. The right moment to read an ADR is when you're looking at the code it explains.
The payoff
The benefits show up in places you wouldn't expect.
- Onboarding is faster. New engineers read the last twenty ADRs and understand the shape of the system and why it's that way, in an afternoon.
- Debates are shorter. "We decided that in ADR 14; has anything in its context changed?" is a far better conversation than starting from scratch.
- Decisions get better. Writing down the alternatives forces you to consider them properly. More than once, I've changed my mind while writing the consequences section.
- Leadership trusts the team more. A visible trail of reasoned decisions makes it much easier to give a team autonomy.
Start small
You don't need to document the history of your system. Start with the next significant decision your team makes. Write it in half an hour, review it like code, and put it in the repo. Then do the next one. In a year, you'll have a record that's more valuable than any architecture diagram, because it explains not just what the system looks like, but why.
Written by Parvez
Engineering Manager at Innova Solutions and a software architect with 25+ years in the industry. I write about leadership, architecture, Java and the books that shaped how I work.
More about me


