Design doc vs RFC vs ADR
Published
Two years from now someone will open your code and ask "why on earth is the rate limiter in the gateway and not in each service?" If the answer lives only in a meeting you had in 2026, they will either guess or undo it. If it lives in a document, they read one page and move on.
Three kinds of document do this job, and people mix up their names all the time:
- A design doc describes how you plan to build one thing, before you build it, so others can find the problems while they are still cheap to fix.
- An RFC (request for comments) is a design doc sent to a wide audience on purpose, usually because the change affects many teams or the whole company.
- An ADR (architecture decision record) is a short note, often under a page, that records one decision and why it was made. It lives next to the code, and you write it after the decision.
The short version: design docs and RFCs are for deciding, ADRs are for remembering.
Your team wants to move from REST calls between two services to a message queue. Your lead asks you to 'write something up'. Which of the three would you write, who reads it, and what are the first three headings?
Design doc: thinking before code#
A design doc is the cheapest place to find a mistake. Changing a paragraph costs minutes. Changing a database schema after three months of data costs weeks. That is the whole argument for writing one.
On a remote team it does a second job: it replaces the meeting. Reviewers in other time zones read it when they are fresh, leave comments, and the decision gets made without everyone being awake at once. That only works if the doc answers the obvious questions before anyone asks them, because each unanswered question is a reply that comes back tomorrow.
Here is a typical first draft of a real kind of doc. Each weak section has the comment a reviewer would leave on it. Fix the sections and watch the comment count.
The public API needs rate limiting.
Make the API fast and reliable.
Add a rate limiter in Redis.
(missing)
We will deploy it next sprint.
(missing)
The six sections in that draft are the ones that matter most:
- Context. What is happening now and why it is a problem. Use real numbers and a real event if you have one. "One customer's retry loop slowed checkout for everyone" beats "we need rate limiting".
- Goals and non-goals. Goals you could check afterwards. Non-goals are the things you are choosing not to do, and they head off half the review comments ("what about billing?").
- The proposal. Enough detail that someone could start building it: where it runs, what it stores, the important numbers, the API. A diagram helps if it has five boxes, not fifty.
- Alternatives considered. The two or three other ways you could do it and why you didn't. Leave this out and every reviewer proposes their favourite, one comment at a time.
- Risks and rollout. What breaks, what happens when a dependency is down, how you ship it gradually and how you undo it.
- Open questions. What you have not decided yet, who decides it and by when. It tells the reader exactly what you want from them.
How long? Most changes need one to three pages. If you need ten, the change is probably large enough to be an RFC, or it is two changes.
The usual failure is a doc that describes the code, not the decision. Pages of class names and field lists, and no line anywhere saying what was rejected or why. A reviewer can't disagree with a list of fields. They can disagree with "we chose a token bucket over a fixed window because fixed windows allow a burst of twice the limit". Write the second kind.
RFC: the same doc, a wider audience#
The name comes from the internet itself. In April 1969 Steve Crocker wrote RFC 1 to share notes on the early ARPANET software, and called it a "request for comments" to sound open rather than final. The IETF still publishes internet standards as RFCs: HTTP, TCP and TLS are all defined in them. Open source projects copied the idea. Rust changes go through RFCs, and Python has PEPs, which work much the same way.
Inside a company, an RFC is a design doc with three differences:
- It goes to everyone affected, often a whole engineering org, not only your team.
- It has a comment window, usually one or two weeks, so people in every time zone get to read it.
- Someone named makes the final call when the window closes, so it can't be talked about forever.
Write an RFC when a change crosses team lines: a new shared library, a new database everyone will use, a change to how services talk to each other, a new rule for on-call. For a change inside your own service, a design doc that your team reviews is enough.
ADR: the decision, remembered#
Michael Nygard proposed ADRs in a 2011 blog post, "Documenting Architecture Decisions". His point was that a team forgets why it chose things, and new people either accept every decision blindly or change it blindly. An ADR fixes that in five short parts:
# ADR 014: Rate limit in the API gateway, not in each service
Status: Accepted (2026-10-20). Supersedes ADR 009.
## Context
One customer's retry loop raised checkout p99 from 180 ms to 2.4 s on 3 Oct.
Limits existed in two services, with different numbers, and none in the rest.
## Decision
A token bucket per API key, checked in the gateway, state in the shared Redis.
## Consequences
One place to change a limit. The gateway now depends on Redis; if Redis is
down we let requests through and page on-call. Services lose per-endpoint limits.ADRs are numbered and stored in the repository, usually in docs/adr/. They are never edited
after they are accepted. When the decision changes, you write a new ADR that supersedes the
old one, so the history of why things changed stays readable in order.
Teams write ADRs after a design doc or RFC has been agreed, and also for smaller decisions that never needed a full doc: "we use UUIDv7 for new primary keys", "we pin Node to the LTS version".
| Choice | What you gain | What you pay | Pick it when |
|---|---|---|---|
| Design doc | Finds design mistakes while they are cheap, and lets reviewers in other time zones weigh in without a meeting. | A few hours to a couple of days of writing, and a review that can stall if nobody owns the decision. | Any change that takes more than about a week, or that is hard to undo. |
| RFC | Everyone affected gets a say, and the decision has wide support when it lands. | Slow: a comment window of one or two weeks, and more people to convince. | Changes that cross teams: shared platforms, company-wide standards, new dependencies. |
| ADR | A permanent, numbered answer to "why is it like this?", stored next to the code. | Almost nothing to write. The cost is the discipline to write one every time. | After any decision someone will question later. Big ones and small ones. |
Malte Ubl wrote about how Google uses design docs in a 2020 post, "Design Docs at Google". The sections he lists are close to the ones above: context and scope, goals and non-goals, the design, alternatives considered, and cross-cutting concerns like security and privacy. His advice on when to skip one is worth copying: if the doc would only say how to build it and nobody would argue with any of it, skip the doc and write the code.
In the interview#
Senior interviews often ask how you made a decision, not only what you built. A doc you wrote is the best possible answer, because it shows your reasoning was on paper before the code.
Checkpoint#
1. Which section of a design doc prevents the most "why didn't you just..." comments?
2. An accepted ADR turns out to be wrong. What do you do?
3. Your change will force four other teams to update their services. What do you write?
- Design docs and RFCs are for deciding. ADRs are for remembering.
- Six sections: context, goals and non-goals, proposal, alternatives, risks and rollout, open questions.
- One to three pages for most changes. Longer usually means an RFC, or two changes.
- ADRs are never edited. A new one supersedes the old one.
- On a remote team, every question the doc leaves open costs a round trip.
A design doc plans one change before it is built, so mistakes are found while they are cheap. An RFC is the same idea sent to everyone affected, with a comment window and a named decider, for changes that cross teams. An ADR is a short record of one decision, stored next to the code, written after the decision and never edited, only superseded. A good design doc has context with real numbers, goals and non-goals, a proposal detailed enough to build from, the alternatives and why they lost, risks and rollout, and open questions with owners. On a remote team the doc replaces the meeting, so I write it to answer the obvious questions up front, because each one left open costs a day.