All posts
guidetemplates

What Makes a Good RFC? A Section-by-Section Breakdown

A practical walkthrough of each section in a well-structured RFC, with examples of what good and bad look like.

DesignDoc Team··7 min read

You've decided to write an RFC. You open a blank document, type a title, and stare at the cursor. What actually goes into this thing?

Most RFC templates include roughly the same sections, but there's a wide gap between filling in the sections and writing something that actually helps your team make a good decision. Let's walk through each section — what it should contain, what it shouldn't, and where people commonly go wrong.

Summary

The summary is a single paragraph — three to five sentences — that tells a reader everything they need to know to decide whether to keep reading. Think of it as the commit message for your entire proposal.

Good:

We propose replacing our current per-request authentication middleware with a session-based approach using signed JWTs stored in HttpOnly cookies. This eliminates the current 40ms per-request token validation call to Auth0, reducing p95 API latency by approximately 15%. Sessions would have a 24-hour lifetime with sliding expiration.

Bad:

This RFC proposes improvements to our authentication system to make it faster and more efficient by using modern best practices.

The good version tells you what's changing (session-based JWTs), why (40ms per-request overhead), and the expected impact (15% latency reduction). The bad version tells you nothing. Every RFC in history could claim to use "modern best practices."

Motivation

This is the most important section. If readers aren't convinced the problem is worth solving, nothing else in the document matters.

A strong motivation section answers three questions: What's the problem? Who does it affect? What happens if we do nothing?

Good:

Our API's p95 latency is 280ms. Tracing shows that 40ms of every request is spent validating the bearer token against Auth0's /userinfo endpoint. For the dashboard, which makes 12 API calls on load, this adds nearly 500ms to the initial render. We've received complaints from three enterprise customers about dashboard load times. Auth0's rate limits also become a concern at our current growth rate — we'll hit the 1,000 req/s limit on our current plan within four months.

Bad:

Our authentication system is slow and outdated. We should modernize it to improve performance and user experience.

The good version has specific numbers (280ms p95, 40ms per call, 12 calls on load), real impact (customer complaints), and a concrete forcing function (rate limits in four months). The bad version is a vibe. You could paste it into any RFC for any system and it would be equally meaningless.

We have a dedicated post on writing motivation sections if you want to go deeper.

Detailed Design

This is where you explain how your proposal works. The level of detail should be proportional to the scope and risk of the change.

For a new API endpoint, show the request/response contract. For a data model change, show the schema. For an architecture change, include a diagram showing how components interact. For a migration, describe the steps and what happens at each stage.

A few principles that separate useful designs from hand-wavy ones:

Be specific about interfaces. If you're proposing a new service, define the API it exposes. If you're adding a database table, show the columns and types. Reviewers can't evaluate a design they can't see.

Call out what changes for existing behavior. If your proposal affects how something works today, explain the delta explicitly. "Currently, X happens. After this change, Y happens instead." Don't make reviewers guess what's different.

Include error cases. What happens when the JWT is expired? What happens if the session store is down? Happy-path designs are easy. The edge cases are where bad designs fall apart.

Don't write a novel. The detailed design should be as long as it needs to be and no longer. If you're writing more than three to four pages, consider whether the scope is too large for a single RFC.

Alternatives Considered

This is where you show your work. The alternatives section isn't a formality — it's one of the most valuable parts of the document.

For each alternative, explain:

  • What the approach is
  • Why it would work
  • Why you didn't choose it

Good:

Alternative: Keep per-request validation, add a local cache. We could cache Auth0 responses for 60 seconds in Redis. This would reduce latency for repeat requests but adds operational complexity (another Redis dependency) and still makes the initial call. It also introduces a cache invalidation window where revoked tokens remain valid. We rejected this because the session-based approach solves the latency problem more completely without the cache invalidation risk.

Bad:

We also considered using Redis but decided not to.

One sentence doesn't count. If you can't articulate why you rejected an alternative, you probably haven't thought about it enough.

Include at least two alternatives. If you can only think of one approach, that's a sign you need to research more before writing the RFC. Three alternatives is a good target — the proposed solution plus two you considered and rejected.

The "do nothing" option is a valid alternative and often worth including explicitly. Sometimes the honest analysis of "do nothing" reveals that the problem isn't as urgent as you thought.

Migration Plan

This section is frequently missing from RFCs, and its absence is usually where proposals fail in practice. A design that can't be deployed incrementally is a design that will stall for months.

The migration plan answers: how do we get from the current state to the proposed state without breaking things?

Good migration plans include:

  • Whether you can deploy incrementally or need a cutover
  • How you handle the transition period when old and new systems coexist
  • What rollback looks like if something goes wrong
  • Feature flags or config changes that control the rollout
  • Data migration steps, if any

For the authentication example:

Phase 1: Deploy session endpoint alongside existing auth middleware. Both paths work. New clients opt in via a feature flag. Phase 2: Migrate internal services to session-based auth over two sprints. Monitor error rates per service. Phase 3: Remove per-request Auth0 validation after all clients have migrated and we've observed stable behavior for one week. Rollback: At any phase, reverting the feature flag restores the original per-request validation path. Session and token auth coexist until Phase 3.

Open Questions

Every honest RFC has unresolved questions. Listing them isn't a weakness — it's a signal that you know what you don't know and want input on those specific points.

Frame open questions as specific, answerable items:

Good:

  • Should session lifetime be 24 hours or 12 hours? Shorter sessions are more secure but increase re-authentication friction.
  • Do we need to support session revocation for admin-initiated logouts, or is natural expiry sufficient for v1?
  • What's our strategy for mobile clients where cookie storage behavior varies across WebView implementations?

Bad:

  • How should we handle edge cases?
  • What do people think about the overall approach?

Vague questions get vague answers. Specific questions get useful ones.

Common Mistakes

Having worked with hundreds of engineering teams, here are the patterns that consistently produce weak RFCs:

Skipping motivation. Jumping straight to the solution because the problem feels obvious to the author. It's rarely as obvious to everyone else. Even if the problem is well-known, quantifying it gives reviewers the information they need to prioritize.

No alternatives. Proposing a single solution with no evidence that other approaches were considered. This makes reviewers suspicious: did you pick the best option, or just the first one you thought of?

Design by committee in the document. RFCs should have a clear author with a clear proposal. It's fine to incorporate feedback, but the document shouldn't try to present three different approaches as equally valid. Take a position.

Too long. An RFC that's 15 pages long won't get read. If the scope is that large, split it into multiple RFCs — one for the overall architecture and separate ones for individual components.

Missing migration plan. A beautiful design with no path from here to there is an academic exercise, not a proposal. The migration plan is often the hardest part. If you don't have one, the RFC isn't ready.

Treating review as a rubber stamp. If you write an RFC expecting it to be approved as-is, you're not actually requesting comments. Be prepared for your proposal to change — sometimes significantly — based on review feedback. That's the process working correctly.

The Minimum Viable RFC

If you're starting from nothing, here's the smallest useful structure:

  1. Summary — What are you proposing? (1 paragraph)
  2. Motivation — Why does this matter? (quantified)
  3. Design — How does it work? (specific enough to implement)
  4. Alternatives — What else did you consider? (at least 2)
  5. Open Questions — What's unresolved? (specific items)

You can add migration plans, security considerations, and other sections as your team's process matures. But those five sections are enough to start having better technical conversations.

Stop losing decisions in Slack and Docs

DesignDoc gives every RFC a structured workflow, inline reviews, and a permanent home.

Get Started