River
Y CombinatorBacked by Y Combinator

Free template

Engineering RFC and Design Doc Template

A nine-section format for proposing a technical change, a worked example, and sheets that track each RFC's status, decision date, objections and sign-offs.

Free download · No account needed

What you get

Pack of 8 files: 5 documents, 3 spreadsheets

Engineering RFC and Design Doc Template
  • How States WorkDocument
  • RFC FormatDocument
  • Review GuidanceDocument
  • Worked RFCDocument
  • Decision RecordDocument
  • RFC RegisterSpreadsheet
  • Comment Resolution LogSpreadsheet
  • Review Sign-offSpreadsheet

How to write an engineering RFC or design doc

An engineering RFC (request for comments), often called a design doc, is a written proposal for a significant technical change, shared so colleagues can challenge it before anyone builds it. A good one measures the problem and names the constraints and earlier decisions it touches. It proposes one design and compares it with the alternatives, including doing nothing. It also explains migration and rollback, lists open questions, and names one decider and a decision date.

Writing it is the easier half. An RFC is finished when someone decides it and writes that decision down, so settle who decides, and by when, from the first draft.

Three men talk at their desks in an open-plan office, with code on a laptop screen beside them
Talk the problem through with the people it affects while the draft is rough. Photo: Austin Distel on Unsplash

Decide whether the change needs an RFC

Write one when the right design isn't obvious. Malte Ubl, formerly an engineering director at Google and now Vercel's CTO, says the central question is whether the solution is ambiguous1. If a doc would only say how you'll build something, with no trade-offs or alternatives, he suggests writing the code instead.

An RFC earns its keep when a change:

  • is hard or expensive to reverse
  • changes an interface, data format or service other teams rely on
  • has two or more serious options and no obvious winner
  • adds work for another team, such as on-call duty or a migration

What goes in an RFC or design doc

Whatever your team calls the sections, cover these. Write the problem before the solution, and give it a number. "Adding a tenant takes 40 minutes of manual broker work" can be checked; "per-tenant topics don't scale" can only be argued with.

The nine sections to cover

SectionWhat goes in itWatch for
HeaderNumber, title, author, status, decider, reviewers and decision dateA committee as decider
ProblemWhat is wrong today, as a measured cost, with its sourceAdjectives instead of numbers
ConstraintsTechnical, organizational and contractual limits that rule options outPreferences posing as constraints
Prior decisionsEarlier decisions this change touches, linkedSkipping one because nobody recorded it
ProposalThe design by component, concrete enough to build fromWhole schemas pasted in
AlternativesOther serious options and doing nothing, each with why it lost"More complex" as the reason
Migration and rollbackHow you get there with the system up, and back if neededWriting it after sign-off
Open questionsEach unanswered question, with an owner or a numbered follow-up"A later RFC" with no number
OperationsWho gets paged; which dashboards, alerts and runbooks changeAlerts firing on the new normal

Leave estimates and task lists for planning, after the decision. If nobody has written down what users need yet, start with a product requirements document.

ExamplePart of a sample RFCAn illustrative example adapted from this template's Worked RFC. The company is made up.

RFC-014: One shared partitioned topic replaces per-tenant topics. Decider: N. Vasquez. Decision due: September 11.

Problem: Our 460 tenants have four topics each. Setting up a tenant takes an engineer 40 minutes, and our last three missed onboarding dates all waited on that step.

Alternatives: Doing nothing grows broker load every quarter. Two topics per tenant keeps the 40-minute setup. Twice the brokers buys about 18 months. A second cluster doubles what we run.

Open question: The partition count can't be reduced later, so RFC-019 will settle it.

  • A cost, not an adjective. Every figure can be checked, so reviewers argue with facts.
  • A follow-up with a number. The open question points at a real RFC, so it can't quietly drop.

Write alternatives and rollback before review

Show the options you turned down, and give each a real reason. "More complex" is a preference; "needs a second consumer group per tenant, so it keeps the cost we're removing" is a reason. Python's PEP 1 asks authors to record rejected ideas with their reasoning, partly to stop people bringing up the same rejected idea again2.

Always include doing nothing and what it costs; if the answer is "not much," you may not need the change. The Rust project warns that RFCs which are disingenuous about the drawbacks or alternatives3 tend to be poorly received.

Write migration and rollback before the formal review. A rollback section added late invites the costliest objection, one that arrives after reviewers have signed off. Name the point of no return, and leave the detailed cutover to a technical migration plan.

Share it early, with a decider and a date

Share a rough draft with the people closest to the problem before it feels finished. In 1969, Steve Crocker's conventions for the first RFCs encouraged notes to be timely rather than polished4. Squarespace saw what happens otherwise: facing review by most of its infrastructure organization, engineers held RFCs back until they were very polished. By then the authors were invested, and major changes weren't welcome5.

Put one decider and a decision date in the header. Tanya Reilly, describing Squarespace's process, writes that naming approvers makes clear where the decision lies5. Make the decider one person, not a committee, so a missed date has an owner. Allow about 2 weeks for a change inside one team and 6 when it crosses several.

Run the review one comment at a time

Ask reviewers to label each comment blocking, non-blocking or a question. Squarespace found that authors flooded with comments struggled to tell blockers from "interesting asides"5. Conventional Comments, a labeling standard for reviews including RFCs, defines a blocking comment6 as one that should prevent acceptance until resolved.

A blocking comment should also say what would resolve it. Squarespace approvers answer "yes" or "not yet" rather than "no," and in its architecture reviews the most common answer is "Yes, if you make sure that…"5

Close every comment, and record how: accepted and the design changed, declined with a reason, answered, or deferred to a numbered follow-up. While any blocking comment is open, don't move the RFC toward a decision.

End with a last call. Rust's process requires every subteam member to sign off before its final comment period begins, often the point when many first review the RFC in full depth3. The period runs 10 calendar days, so it's open for at least 5 business days.

Record the outcome with an honest status

Draft, in review and approved can't tell a decided no from a parked maybe, or an accepted RFC from a built one. Kubernetes' proposal template allows seven statuses: provisional, implementable, implemented, deferred, rejected, withdrawn and replaced7. The distinctions worth keeping:

  • Accepted: decided yes, not yet built.
  • Implemented: shipped and in service.
  • Rejected: decided no, with the reasoning kept.
  • Withdrawn: pulled by its author.
  • Superseded: replaced by a later RFC, linked both ways.
  • Deferred: nobody is working on it.
  • Postponed: the team chose to wait, and named what will reopen it.

PEP 1 lets an author or editor mark a proposal Deferred when no progress is being made2, which says nothing against the idea. Accepted isn't done either. Rust's RFC process says acceptance implies nothing about priority or about who will build it. Every accepted RFC there gets an issue tracking its implementation3, and its author isn't obliged to build it, so name an owner.

Then write the decision down: what was decided, who decided it, where, and which objections were overruled. PEP 1 makes authors responsible for documenting dissenting opinions2, and says a decided proposal should show its new status and link to the post that made the decision. File the outcome as an architecture decision record.

Once a month, sweep for RFCs past their decision date, silent for 60 days or accepted with no owner.

Before you ask for a decision

  • The problem states at least one measured cost
  • Every alternative, including doing nothing, says why it lost
  • Migration and rollback name the point of no return
  • Every open question has an owner or a numbered follow-up
  • The header names one decider and a decision date
  • No blocking comment is still open
  • Every required reviewer has signed off

If the agreed design needs a security review, take it through a STRIDE threat model next. To start faster, open this template in River, which builds the register from the RFCs you already have.

How to use this template

Use the files on their own: copy the nine sections in RFC Format for each proposal, add it to the RFC Register, and log every review comment in the Comment Resolution Log. The Worked RFC shows a finished proposal to aim for.

Or open them in River with Edit with AI. Send whatever you have: a draft, a problem you want to solve, or your team's existing RFCs. River fills the register and comment log, reports which proposals are past their decision date or waiting on an unanswered objection, and suggests status changes for you to approve.

  1. Download it or open it in River

    Get the five Word documents and three CSV sheets free, or open the template in River and bring the RFCs you already have.

  2. Send what you already have

    Share a draft, a problem or your team's existing RFCs. River builds the register and comment log, then reports what has stalled.

  3. Draft and review the proposal

    Write it in the nine-section format, or ask River to draft it, review it from a named role or close out a comment.

  4. Decide it and record it

    Once no blocking comment is open, set the status, name an owner and write the decision record. Sweep stalled RFCs monthly.

What's in the template

Why has this not moved, answered with a numberEvery blocking count is recomputed from the comment log. Nothing in that column was typed in by a person.
Engineering RFC and Design Doc Template
RiverRFC Register

RFC Register

Kestrel Data, a fictional streaming analytics platform. Status On Document is the header transcribed. Status is the normalized state. Blocking is a join against the comment log.

RFCTitleHeader saysStatusDuePast dueSign-offsBlockingImpl. owner
RFC-014Shared partitioned topicIn ReviewFinal Comment Period2026-09-1135 of 51—
RFC-017One ingest specificationIn ReviewIn Review2026-05-181193 of 42—
RFC-009Query planner in RustIn ReviewIn Review2026-08-04412 of 41—
RFC-015SDKs from the descriptionDraftIn Review2026-09-2801 of 40—
RFC-013Jobs on the batch clusterDraftDraft2026-09-2101 of 40—
RFC-006Tracing across every serviceIn ReviewDeferred2025-10-20n/a2 of 42Unassigned
RFC-016Drop Python 3.9In ReviewDeferred2026-03-02n/a1 of 40Unassigned
RFC-011Service mesh east-westOn holdPostponed2026-06-10n/a4 of 40—
RFC-003One error envelopeApprovedAccepted2025-11-17n/a4 of 40Unassigned
RFC-012One flag evaluation serviceApprovedAccepted2026-06-15n/a4 of 40Unassigned
RFC-008Tiered storage past 30 daysApprovedProvisional2026-03-23n/a4 of 40P. Adeyemi
RFC-001Semantic versioningAcceptedImplemented2025-07-28n/a4 of 40L. Marchetti
RFC-004Deploy-time DB credentialsRejectedRejected2025-11-24n/a4 of 40n/a
RFC-005Jobs off the app clusterDraftWithdrawn2026-01-26n/a1 of 40n/a
RFC-018Retire internal metrics formatImplementedSuperseded2025-09-22n/a4 of 40n/a

18 rows, all 11 states represented. A three-state template renders 5 of these as In Review; here they read Draft, In Review three times and Final Comment Period, and 3 are past a date they set themselves. Nine headers name a different state than the register does: some flatter the proposal, and others lag behind its progress. Four more differ only in wording, where Approved normalizes to Accepted and On hold to Postponed, and the sheet counts those separately.

RiverComment Log

Comment Resolution Log

One row per comment. A class chosen by the reviewer before they type, then a disposition that requires a person, a date and where it was written down.

IDRFCConcernClassDispositionDays openChanged design
C-011RFC-006Instrumenting every service needs an owner per service and there is no listBlockingOpen335—
C-012RFC-006The sampling decision belongs at the edge, not inside each serviceBlockingOpen328—
C-031RFC-017One specification for two API versions needs a stated deprecation pathBlockingOpen139—
C-032RFC-017Generated reference would replace the handwritten guides nobody ownsBlockingOpen131—
C-021RFC-009No number here says what the current planner costs, so there is nothing to beatBlockingOpen84—
C-045RFC-014The migration needs a rollback that does not lose in-flight eventsBlockingOpen31—
C-022RFC-009Two engineers can maintain the current planner and one of them is leavingNon-blockingOpen76—
C-041RFC-014A shared topic lets one tenant's replay throttle every other tenant's ingestBlockingAccepted, design changed10Yes
C-042RFC-014Per-tenant retention becomes impossible once the topic is sharedBlockingAccepted, design changed10Yes
C-043RFC-014Partition count cannot be reduced later, so the first number is a one-way doorBlockingDeferred to a follow-up13No
C-044RFC-014Call it a shard rather than a partition, to avoid the broker's own termNon-blockingDeclined with reason2No
C-046RFC-014Does this change what the client library has to do on reconnectQuestionAnswered, no change needed1No
C-002RFC-004Even revised, the rotation window is longer than the incident it should containBlockingAccepted, RFC rejected6No

16 comments in the shipped sheet: 12 blocking, 3 non-blocking, 1 question. Six blocking are still open, and they are the register's whole blocking count. C-011 was raised by the decider, nobody argued with it, nobody produced the list, and the author of RFC-006 left the company in March. C-045 is the expensive shape: the operability reviewer had already signed off, the migration section landed afterwards, and the objection arrived three days later while nobody was looking. Five comments changed a design, which is the healthiest number on the sheet.

RiverSign-off

Review Sign-off

Position and depth are separate columns, because signing off and reading are separate events.

RFCReviewerRoleRequiredPositionDepthNote
RFC-014R. VillalobosOperabilityYesSigned offRead in fullSigned off, then raised C-045 once the migration section landed
RFC-014T. BergqvistQuery ownerYesSigned offRead in fullSigned off with C-043 deferred to RFC-019 by agreement
RFC-017H. NakagawaStorage ownerYesSigned offSkimmedRecorded as skimmed at the reviewer's own request
RFC-017N. VasquezDeciderYesSigned offRead in fullRaised C-031, still open
RFC-017R. VillalobosOperabilityYesNot lookedNone—
RFC-006J. OkonkwoAuthorYesSigned offRead in fullAuthor. Left the company in March 2026
RFC-006S. OyelaranSecurityYesNot lookedNone—
RFC-015H. NakagawaStorage ownerNoNot requiredn/aRecorded as not required, so the empty row is a ruling rather than a gap
RFC-013N. VasquezDeciderYesNot lookedNone—

26 rows in the shipped sheet: 14 signed off, 11 not looked, 1 ruled not required. Depths run 13 read in full, 1 skimmed. RFC-014 reached a final comment period because 5 of 5 signed off, which is the gate Rust's process describes, and it is still sitting there with a blocking comment open. RFC-006 shows the other failure: two of four required reviewers never opened it, and for eleven months its header said In Review, so nobody read that as a problem.

  • How States WorkThe 11 statuses a proposal can hold, from draft to deferred, and what tells each apart.
  • RFC FormatThe nine sections with guidance for each, and why estimates, task lists and signature blocks stay out.
  • Review GuidanceHow to label comments blocking, non-blocking or question, close each one, and the order to read in.
  • Worked RFCA finished proposal for a made-up company, with measured costs, four alternatives and a phased rollback.
  • Decision RecordOne entry per resolved proposal: what was decided, who decided it, where, and why.
  • RFC Register sheetOne row per proposal: its status as written and as it stands, decision date, sign-offs and open objections.
  • Comment Resolution Log sheetEvery review comment, its class, how it was closed and by whom, and whether the design changed.
  • Review Sign-off sheetEach reviewer a proposal needs, their position, and whether they read it in full or skimmed it.

Common questions

What is an RFC in software engineering?

An RFC, short for request for comments, is a document proposing a technical change so that colleagues can question it before anyone builds it. Many companies call the same document a design doc. The name dates from 1969, when a small group of network researchers began numbering its working notes "Request for Comments."

What should an RFC template include?

A good RFC template opens with a header naming the author, status, one decider, the required reviewers and a decision date. Then come the problem with measured costs, the constraints, earlier decisions it touches, the proposal, alternatives including doing nothing, migration and rollback, open questions and the effect on operations. Estimates and task lists wait until after the decision.

How long should a design doc be?

Long enough to settle the decision and short enough that every reviewer reads all of it. Malte Ubl, writing about design docs at Google, puts the sweet spot for a larger project at around 10 to 20 pages, and says a "mini design doc" of 1 to 3 pages suits incremental changes. This template's format aims for under 2,000 words.

Who should review an RFC?

Anyone who owns something the change touches. Squarespace's RFC template suggests approvers from four groups: potential users of the system, teams that run systems it depends on, maintainers of internal systems you considered but did not choose, and anyone expected to do extra work. Mark which reviewers must sign off, and name one person who decides.

What is the difference between an RFC and an architecture decision record?

An RFC is the argument, made while a change is still undecided, so it carries alternatives, open questions and review comments. An architecture decision record is the verdict, written once the decision is made and left as written afterward. Teams that keep both write the RFC first, then one short record per decision it settles.

Is this RFC template free?

Yes. Download the five Word documents and three CSV sheets with no signup. The sheets come filled with a made-up company's 18 proposals, 16 review comments and 26 sign-off rows, so you can see how they work before clearing them. Edit with AI opens the same template in a free River workspace.

What does Edit with AI do?

It opens the template in a free River workspace and asks for what you have: a draft, a problem or your team's existing RFCs. River builds the register and comment log from them, then reports which proposals are past their decision date or held up by an unanswered objection. It suggests status changes and waits for you to agree.

Sources

  1. Malte Ubl. “Design Docs at Google.” industrialempathy.com (opens in a new tab)

  2. Python Enhancement Proposals (PEPs). “PEP 1 – PEP Purpose and Guidelines.” peps.python.org (opens in a new tab)

  3. GitHub. “rust-lang/rfcs: RFCs for changes to Rust.” github.com (opens in a new tab)

  4. RFC Editor. “RFC 3: Documentation conventions.” rfc-editor.org (opens in a new tab)

  5. Squarespace Engineering. “The Power of “Yes, if”: Iterating on our RFC Process.” engineering.squarespace.com (opens in a new tab)

  6. Paul Slaughter. “Conventional Comments.” conventionalcomments.org (opens in a new tab)

  7. GitHub. “enhancements/keps/NNNN-kep-template/kep.yaml at master.” github.com (opens in a new tab)

Written by

Chandler Supple

Co-founder & CEO, River

Chandler has spent the last six years working in AI, building tools for millions of users and Fortune 100 companies. In 2025, he co-founded River to build a new kind of operating system for AI agents.

Reviewed by

Brian Joseff, Co-founder, River