Library
10 min read

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 answer

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.

Review a design doc before anyone else does
Add rate limiting to the public API. Draft 1.6 open comments
Context

The public API needs rate limiting.

Why now? What happened, and who was hurt? I can't judge the fix without the problem.
Goals and non-goals

Make the API fast and reliable.

How will we know this worked? And is usage billing in scope? Sales has been asking.
Proposal

Add a rate limiter in Redis.

Where does the check run, what are the limits, and which Redis? We have three.
Alternatives considered

(missing)

Did you look at doing this at the CDN? Or a fixed window? Why not those?
Risks and rollout

We will deploy it next sprint.

What happens if Redis goes down? Do we reject every request? How do we roll back?
Open questions

(missing)

Is anything still undecided, or is this final? I can't tell what you want from me.
6 comments, each a question only you can answer. With a 5 hour gap to the reviewer, each answer lands the next working day, and some answers raise new questions. This is how a one week change takes three weeks.

The six sections in that draft are the ones that matter most:

  1. 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".
  2. 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?").
  3. 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.
  4. 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.
  5. Risks and rollout. What breaks, what happens when a dependency is down, how you ship it gradually and how you undo it.
  6. 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 doc nobody reads

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:

md
# 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".

Which one would you write?
Your team is replacing its own cron jobs with a queue and workers.
Every service in the company must move from API keys to mTLS within a quarter.
You decided last week to store money as integer paise, never as floats.
You are renaming a private function.
ChoiceWhat you gainWhat you payPick it when
Design docFinds 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.
RFCEveryone 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.
ADRA 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.
In the wild

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.

Interviewer
Tell me about a technical decision you had to get other people to agree with.
A behavioural question, but they are scoring how you reason and how you work with others.
You
We had one customer's retry loop slow checkout for everybody. I wrote a two page design doc: the incident with numbers, goals I could measure afterwards, a token bucket in the gateway as the proposal, and why we rejected per-service limits and the CDN option. The first review raised the question of what happens if Redis is down, which I hadn't covered. I added fail-open with a page to on-call. Two teams in Europe commented overnight and we had agreement in three days without a meeting. Then I wrote a short ADR so the next person knows why it lives in the gateway.
Context with numbers, alternatives, a gap a reviewer found and how it was fixed, and the decision recorded for later.
Interviewer
What if someone senior had disagreed?
You
I would ask what they were worried about and add it to the doc, either as a risk with a plan or as a reason to change the proposal. If we still disagreed after one round, I would ask for a short call, then write the outcome back into the doc so the reviewers who weren't on it can see what changed.
Treats disagreement as input, and keeps the written record as the source of truth.

Checkpoint#

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?

Worth memorising
  • 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.
Say this in 60 seconds

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.