Design doc template: how to write, review and track a software design doc
A copy-paste design doc and RFC template with section-by-section guidance, when to write an ADR instead, a review process, and how to link the doc to its PRs.
The KnowWhyy team · · 9 min read
A big change gets talked through in a meeting, someone starts coding, and the real design review happens in the comments of a 2,000-line pull request. By then the expensive choices are already made. A year later, a new engineer asks why the system works this way, and the only answer is a whiteboard photo nobody can find.
A design doc moves the debate to where changing your mind is cheap, and leaves a record of why. Here is a template, guidance for each section, a clear rule for when an ADR fits better, a light review process, and a way to tie the doc to its PRs.
What a design doc is for
Malte Ubl's article Design Docs at Google describes them as relatively informal documents written before coding starts, which capture the high-level implementation strategy and key design decisions "with emphasis on the trade-offs that were considered." The article lists what they do beyond documenting the design: catch design issues early while changes are cheap, build consensus, make sure cross-cutting concerns like security and privacy get considered, spread senior engineers' knowledge, and form an organizational memory of design decisions.
Open source projects use the same idea under the name RFC. The Rust RFC process exists so that "substantial" changes go through a design process and reach consensus before they are built, while bug fixes and small improvements go through normal pull requests.
When to write one (and when not to)
Writing a design doc is overhead. The Google article says the decision comes down to whether the solution is ambiguous, because of problem complexity, solution complexity or both. If the doc would just say "this is how we'll implement it" without trade-offs or alternatives, skip it and write the code.
The article ends with five questions. Paraphrased:
Ask your first question in minutes.
Create a workspace, connect a tool and choose what gets indexed. The free plan includes GitHub, Slack and Notion.
Are you unsure about the right design, and would upfront time buy certainty?
Would it help to involve senior engineers who can't review every code change?
Is the design ambiguous or contentious enough that consensus would be valuable?
Does your team sometimes forget privacy, security, logging or other cross-cutting concerns?
Do you need high-level documentation of legacy systems?
If you answer yes to three or more, the article suggests a design doc is probably worth it.
Rust's README gives a complementary list of changes that don't need an RFC: rephrasing or refactoring that changes shape but not meaning, changes that strictly improve objective measures like speed or warnings, and changes only other maintainers would notice. That list translates well to most teams.
Design doc vs ADR
Teams often confuse these. They solve different problems and work best together.
Design doc / RFC
ADR
Question it answers
"How should we build this, and why this way?"
"What did we decide about X, and why?"
When
Before building, while the design is open
When a decision is made, often during or after a design doc
Scope
A whole feature or system; many decisions
One decision
Length
1-3 pages for a "mini" doc, roughly 10-20 for a large project (per the Google article)
Updated while being built; becomes historical once shipped
Never edited; a new ADR supersedes it
Lives in
Docs tool or repo, wherever review is easiest
The repo, next to the code
The simple rule: write a design doc to make a decision together, and an ADR to record a decision durably. A design doc for a new billing system might produce three ADRs: "use Postgres for the ledger," "store money as integer cents," and "events go through the outbox pattern." Each ADR links back to the design doc for the full discussion. The design doc lists the ADRs it produced.
If the choice is narrow and the options are clear (pick a queue, adopt a library), skip the design doc and write the ADR directly. Our guide to architecture decision records that stick has a short template and clear triggers for when one is required.
The design doc template
This combines the structure from the Google article (context, goals and non-goals, design, alternatives, cross-cutting concerns) with sections from Rust's RFC template that teams often miss: drawbacks, prior art and unresolved questions. The header adds the links that keep the doc connected to the work.
# Design: <short name>
Status: Draft | In review | Approved | Implemented | Abandoned | Superseded by <link>
Author(s): <names> Reviewers: <names>
Created: <YYYY-MM-DD> Review deadline: <YYYY-MM-DD>
Tracking issue: <link> Related ADRs: <links>
Discussion: <Slack thread or review PR link>
## Summary
Three to five sentences. What you propose and why, readable on its own.
## Context
Background facts a reader needs. What exists today, what's wrong with it,
links to data. No proposals here.
## Goals
- Bullet list of what this design must achieve. Measurable where possible.
## Non-goals
- Things that could reasonably be goals but are explicitly out of scope.
## Proposed design
### Overview
One paragraph and a diagram showing the system in its surroundings.
### Details
APIs, data model, key flows. Only the parts that matter for the trade-offs.
### Rollout and migration
How it ships: flags, phases, backfills, how to roll back.
## Alternatives considered
For each: a short description, its trade-offs, and why it lost.
Include "do nothing".
## Drawbacks
Honest costs of the chosen design.
## Cross-cutting concerns
- Security and privacy:
- Observability (metrics, alerts, runbooks):
- Cost and capacity:
- Testing:
## Prior art
How others (inside or outside the company) solved this, and what we learned.
## Open questions
What still needs an answer, and who will answer it by when.
## Implementation
| PR / issue | What it does | Status |
| ---------- | ------------ | ------ |
Section-by-section guidance
Summary. Write it last. Many readers stop here. If you can't summarize the design in five sentences, it probably isn't settled yet.
Context. The Google article says this section should be "entirely focused on objective background facts." Keep opinions and proposals out. Link to dashboards, incident postmortems or support data instead of describing them. A reviewer who disagrees with your context will disagree with everything after it, so make it easy to verify.
Goals and non-goals. Non-goals do the most work. The article's point is that a non-goal is not a negated goal ("the system shouldn't crash") but something you could reasonably want and chose not to pursue. "Support multiple currencies" as a non-goal saves a week of review comments.
Proposed design. Start with an overview, then go into detail. Sketch APIs and data models only where they affect the trade-offs; the Google article warns against pasting full schemas or interface definitions because they are verbose and go out of date quickly. Link to a prototype if you have one. As the article puts it, "I tried it out and it works" is one of the best arguments for a design.
Alternatives considered. The Google article calls this one of the most important sections, because it shows why the chosen design beats the options a reviewer is probably wondering about. Rust's template asks a useful extra question: what is the impact of not doing this at all? Always include "do nothing" as an option.
Drawbacks. Rust's README notes that RFCs which are "disingenuous about the drawbacks or alternatives tend to be poorly-received." Naming the costs yourself builds trust and saves reviewers from hunting for them.
Cross-cutting concerns. Standardize the list for your team so nobody has to remember it. Security, privacy, observability and cost cover most cases. If the design adds alerts, say which runbooks will need writing (see our runbook template).
Open questions. Rust's template separates questions to resolve before approval from questions to resolve during implementation. Do the same. It tells reviewers which comments are blocking.
Implementation. Empty when you start. It fills in as PRs land, which is what keeps the doc connected to the code (more below).
A review process that doesn't stall work
The Google article describes a range: from sending the doc to the team list and discussing in comment threads, to formal design review meetings with senior engineers. It also warns that reviews can become "a dangerous trap of overhead," and that waiting for scheduled review meetings can slow development. Rust uses a heavier, very explicit process: the RFC is a pull request, discussion happens in the PR thread, and once the trade-offs are clear a team member proposes a final comment period with a disposition (merge, close or postpone). Every member of the relevant team must sign off before it starts, and it lasts ten calendar days so stakeholders have time to raise objections.
Most product teams need something in between:
Draft with one or two close collaborators. Iterate fast until the design is stable enough to share.
Request review with a deadline. Name the required reviewers and give them a date, usually three to five working days.
Discuss in comments, decide in a short meeting only if needed. Keep threads in the doc or PR. If comments go in circles, book 30 minutes with the people involved, and post a summary back in the doc.
Record the decision. Change the status to Approved or Abandoned, note who approved, and write ADRs for the key decisions.
A review request that gets responses:
Design review: Ledger service for billing (design-042)
Doc: <link>
Required reviewers: @maya (payments), @devon (data), @lee (security)
Please review by: Thu 2026-11-12
Most useful feedback: the data model (section 4.2) and whether the
outbox approach is overkill for our volume (Alternatives, option B).
Not looking for: naming feedback yet.
If you want review in Git, the Rust model works well inside a company too: put design docs in a docs/design/ folder, open each as a PR, and merge it when approved. Rust asks authors not to squash or rebase commits once they're visible on the PR, so reviewers can see how the design changed in response to feedback.
Keep the doc linked to the PRs that build it
A design doc that stops at "Approved" loses most of its value. Six months later someone finds the code and has no idea a design doc exists, or finds the doc and can't tell what actually shipped.
Give the doc an ID and a tracking issue. Every accepted Rust RFC has an associated issue tracking its implementation. Do the same: create one issue per approved design, put its link in the doc header, and give the doc a short ID like design-042.
## Context
Design: design-042 (<link to doc>)
Part of #318
On GitHub, referencing an issue such as #318 or owner/repo#318creates a backlink on that issue by default, so the tracking issue collects every PR that mentions it. Use a closing keyword like Closes #318 only in the final PR: closing keywords close the issue when the PR merges, and they only work when the PR targets the default branch.
Find all the implementing work in one command:
gh pr list --repo acme/billing --state all \
--search "design-042 in:body" --json number,title,state,url
Update the doc while you build. The Google article is direct about this: if the system hasn't shipped yet, update the doc when the design changes. After launch, add amendments as new linked docs rather than rewriting history. Rust treats accepted RFCs the same way: minor changes go in as amendments, and substantial changes need a new RFC with a note added to the original.
Close the loop. When the work ships, set the status to Implemented, fill in the Implementation table, and link the doc from the service's README. That one link answers the question the Google article says engineers often ask first about an unfamiliar system: "Where is the design doc?"
Where KnowWhyy fits
Even well-linked design docs get separated from their context: the Slack thread where the real debate happened, the PR comment that changed the plan, the follow-up issue. KnowWhyy indexes the GitHub repos, Slack channels and Notion pages you choose (PRs, issues, commits and discussions, not source code). In the web app you can ask "why did the ledger design switch to the outbox pattern?" or "which PRs implemented design-042?" and get an answer that links to each PR, thread and page it used. If the indexed sources don't contain the answer, it says so. It won't write or review the design doc for you; it makes the trail around it easy to follow later. See engineering onboarding or start free.
The short version
Write a design doc when the solution is ambiguous or contentious; skip it when the doc would just be an implementation plan.
Use a design doc to decide together and an ADR to record each decision; the design doc links its ADRs and each ADR links back.
Cover context, goals and non-goals, the design, alternatives (including "do nothing"), drawbacks, cross-cutting concerns and open questions.
Review with named reviewers and a deadline, discuss in comments, and record the outcome in the status field.
Give each design an ID and a tracking issue, reference it in every implementing PR, and keep an Implementation table in the doc.