Engineering Management ·

Writing RFCs That Drive Alignment: A Practical Template for Engineering Teams

Most internal engineering docs fail because they are too long, written after the decision, or have no clear ask. This guide covers a practical RFC template, the full RFC lifecycle, and how to run the process without design-by-committee.

Writing RFCs That Drive Alignment: A Practical Template for Engineering Teams

Most internal documentation fails in one of three ways: written after the decision is already made, too long for anyone to finish, or missing a clear ask so nobody knows what to do with it.

RFCs (Requests for Comments) are supposed to solve this. Used well, they create shared context before decisions are locked, surface tradeoffs the author missed, and give distributed teams a way to align without synchronous meetings. Used badly, they become a bureaucratic ritual that produces watered-down decisions.

This guide covers how to write RFCs that get read and drive real alignment.


Why Most Internal Docs Fail

Before getting into the template, it is worth naming the failure modes precisely, because they are distinct problems with distinct fixes.

Written after the decision. The author has already chosen an approach and is documenting it. The RFC becomes a formality. Reviewers sense this and either rubber-stamp it or, if they object, create conflict after the team has already committed emotionally and logistically. If you are writing an RFC for a decision that is already made, stop. Write an ADR (Architecture Decision Record) instead and be honest that this is documentation, not a proposal.

Too long to read in a single sitting. An RFC that takes 45 minutes to read will get skimmed. The most important sections will be missed. The context that would have prompted the right objections never gets absorbed. If your RFC needs to be longer than 1,500 words to make its case, the proposal is probably not well-scoped yet.

No clear ask. “I am sharing this for awareness” is not an RFC. You need to explicitly state what kind of feedback you want, who has to approve it, and what happens when the review period closes. Without this, feedback is scattered and the RFC never closes.

Design by committee. Leaving the RFC open for two weeks with no structure invites every opinion with no way to resolve disagreement. An RFC is not a vote. The author drives the decision; the process surfaces information.


The RFC Template

Use this structure. Every section has a job. Skip sections only when you can articulate why they do not apply.

# RFC: [Short descriptive title]

**Author:** [Name]
**Status:** Draft | Under Review | Accepted | Rejected | Superseded
**Created:** [Date]
**Review deadline:** [Date, typically 5-7 business days from posting]
**Approvers:** [List the people whose sign-off is required]

## Context and Problem

[2-4 paragraphs. What is the current situation? What is the pain?
Reference specific incidents, metrics, or constraints. Do not
propose a solution here. This section answers: why does this matter?]

## Proposed Solution

[The specific approach you are recommending. Be concrete.
Include diagrams, pseudocode, or API sketches where they
clarify the proposal. This section answers: what exactly are
we doing?]

## Alternatives Considered

[At least two alternatives you evaluated before landing on the
proposal. For each: what it is, why it was not chosen. This
signals intellectual honesty and saves reviewers from
re-raising paths you already evaluated.]

## Tradeoffs

[A direct statement of what you are giving up. Every decision
optimizes for some dimensions at the expense of others. Name them.
A tradeoffs table works well here.]

## Rollout Plan

[How this gets implemented. Phases, dependencies, feature flags,
migration steps. If rollout can go wrong, describe what that looks
like and how you roll back.]

## Open Questions

[Questions you have not answered yet and need input on.
This is where reviewers should focus their energy if they
have relevant expertise.]

## Appendix (optional)

[Supporting data, previous discussions, links to relevant code or docs.]

That is the full template. The next sections explain how to use each part.


Writing Each Section Well

Context and Problem

This is the most important section and the one most authors underwrite. A good context section does three things: it describes what is actually happening today (not what you wish were happening), it explains why the current state is a problem worth solving, and it establishes the scope of the decision.

Cite specifics. “Our REST API is becoming hard to maintain” is vague. “In the last quarter, three separate teams made incompatible changes to /api/users because there was no contract between consumer and provider, and we resolved two of them with runtime patches after they hit production” is something reviewers can evaluate. Specifics also prevent the RFC from reopening scope debates that the context already settles.

Do not propose a solution in this section. The problem statement and the solution are separate. Authors who conflate them are usually advocating for a conclusion they reached before writing the RFC.

Proposed Solution

Be specific to the point of discomfort. Vague proposals produce vague feedback. If you are proposing a GraphQL migration, say which schema-first tooling you plan to use, how you will handle authentication, and what the subscription story looks like. If those details are not settled, surface them in Open Questions, not by leaving the proposal ambiguous.

Diagrams earn their weight here. A sequence diagram showing how data flows through the proposed architecture covers in ten seconds what three paragraphs of prose would obscure.

Alternatives Considered

This section does something psychological as much as technical: it signals to reviewers that you did the homework. If a reviewer’s first instinct is “but have you considered X,” and X is already in Alternatives Considered with a clear reason it was not chosen, that objection is resolved before it is raised.

Two alternatives is the minimum. One of them should be “do nothing,” even if it is obviously wrong. The cost of the status quo is relevant context.

Tradeoffs

Name what you are giving up. Every choice optimizes for some set of constraints at the cost of others. If you cannot articulate what you are trading away, you have not finished thinking.

A table works well here:

DimensionCurrent StateProposed State
Developer ergonomicsInconsistent REST conventionsGraphQL schema as shared contract
Query flexibilityFixed endpoints, over/under-fetchingArbitrary query shape
Operational complexitySimple to monitor and cacheN+1 risk, query depth limits required
Migration costN/A4-6 weeks of parallel operation
Client SDK maintenancePer-team, ad hocAuto-generated from schema

A tradeoffs table this concrete tells reviewers exactly where to apply their expertise. A reviewer who has deep experience with GraphQL in production will immediately go to operational complexity and add nuance you missed.

Rollout Plan

This section separates proposals that are ready for implementation from proposals that are still in the thinking stage. A good rollout plan has phases, identifies dependencies, and addresses what happens when it goes wrong.

If the change is reversible, say so and describe the rollback path. If it is not reversible, that is worth stating explicitly because it raises the bar for the decision.

Open Questions

This is where reviewers should focus their energy. An RFC with no open questions is either very mature or has not been thought through carefully enough to know what is unknown. Both are possible; the author should know which one applies.

Order open questions by how much they affect the proposal. If the answer to question one would change the proposed solution entirely, say that.


The RFC Lifecycle

An RFC moves through four states. Each state has a clear definition and a clear transition condition.

Draft: The author is still writing. Share drafts for informal feedback, but mark them clearly so reviewers know their comments are pre-review.

Under Review: The RFC is posted with a concrete end date, typically five to seven business days. The author responds to comments and updates the RFC as feedback arrives.

Accepted or Rejected: The review period has closed and a decision is made. Rejected RFCs should include a brief note on why, so the same discussion does not happen again in six months.

Superseded: The RFC was accepted and implemented, but a later decision changed the approach. Mark it superseded with a link to the new RFC. Never delete old RFCs; the reasoning chain matters.

One state easy to abuse: leaving an RFC “Under Review” indefinitely because nobody wants to make a call. Set a review deadline when you post it. If the deadline passes without resolution, schedule a 30-minute synchronous decision meeting with the approvers, make the call, and close it.


Running the Review Without Design by Committee

The most common failure mode after the template is the feedback phase. A well-written RFC gets posted to a Slack channel, twenty people comment over two weeks with contradictory opinions, and the author either capitulates to the loudest voice or gets paralyzed trying to synthesize irreconcilable positions.

A few practices that prevent this:

Name approvers explicitly. The RFC process is not a democracy. A small set of named approvers (two to four people) have blocking authority. Everyone else can comment for consideration but cannot block. This distinction has to be explicit or it will not be respected.

Distinguish blocking from non-blocking feedback. Ask reviewers to prefix comments with [blocking] or [non-blocking]. A blocking concern would change the decision if unresolved. A non-blocking one is worth noting but does not derail the process. This forces reviewers to be honest about the strength of their positions.

Respond to every comment. Even if the response is “acknowledged, not changing the proposal because X.” This closes the loop and signals the feedback was read. An RFC with twenty unanswered comments looks abandoned.

Close the RFC when the review period ends. An RFC that stays open past its deadline signals nobody is in charge. Close it. If more discussion is needed, extend the period explicitly with a new deadline.


A Real Example: Migrating from REST to GraphQL

Here is what a real RFC looks like in practice. This is condensed but reflects the structure and specificity that makes an RFC useful.


RFC: Migrate Public API to GraphQL

Author: Maria Chen Status: Under Review Created: 2026-02-01 Review deadline: 2026-02-10 Approvers: Head of Engineering, Mobile Lead, Backend Lead

Context and Problem

Our mobile and web clients each maintain separate API integration layers against our REST endpoints. Over the past two quarters, we have shipped three features where mobile and web had different assumptions about the response shape of /api/orders and /api/users/profile. Two of these caused production incidents. In each case, the root cause was that there was no formal contract between the API and its consumers.

Additionally, our mobile client consistently over-fetches: the /api/orders endpoint returns 34 fields, of which the list view uses 6. This accounts for roughly 18% of our mobile payload size.

The problem is not REST per se. The problem is that our REST implementation has no schema enforcement and no ergonomic way for clients to request only the data they need.

Proposed Solution

Replace the public-facing REST API with a GraphQL API using Apollo Server on the backend and auto-generated TypeScript clients via graphql-codegen. The REST endpoints remain available internally between services.

Schema definition will be code-reviewed like any other code. Consumers query the schema; they do not query endpoints. Breaking changes to the schema require a deprecation period of at least one release cycle.

Rollout:

  1. Stand up GraphQL server alongside REST. Both serve the same data.
  2. Migrate web client over four sprints. REST endpoints remain.
  3. Migrate mobile client in the following release cycle.
  4. Deprecate REST public endpoints 90 days after mobile migration completes.

Alternatives Considered

Keep REST with OpenAPI schema enforcement. We evaluated adding strict OpenAPI validation to our existing REST implementation. This solves the contract problem but not the over-fetching problem. It also requires retrofitting schema enforcement onto 47 existing endpoints, each of which has inconsistencies that would surface as breaking changes. Estimated effort: 6-8 weeks with significant coordination risk across teams.

Do nothing. The status quo produces roughly one API contract incident per quarter. Each incident takes 2-4 hours to resolve. The over-fetching problem compounds as the mobile client grows. Not acting has a cost; it is just paid in smaller increments.

Tradeoffs

DimensionREST (current)GraphQL (proposed)
Schema contractNone enforcedStrict, code-reviewed
Over-fetchingSystematicEliminated by design
Operational complexitySimpleNeeds query depth limits, cost analysis
CachingHTTP-level, freeRequires explicit strategy
Team familiarityHighLow (training required)
Migration costN/A10-14 weeks estimated

Open Questions

  1. How do we handle authentication tokens across the GraphQL layer? Current auth middleware is REST-specific. This could affect the rollout timeline if it requires refactoring the auth layer first.
  2. What is the query complexity limit? We need a concrete number before the backend implementation starts.
  3. Should subscriptions be in scope for the initial migration, or deferred?

That RFC is complete enough to review in 15 minutes, concrete enough to surface real objections, and honest about what is unknown.


When NOT to Write an RFC

Not every decision needs an RFC. Writing one when the decision does not warrant it adds process overhead without alignment benefit.

Skip the RFC when the decision is easily reversible and scoped to one team. If a backend team wants to try a new library for a non-critical service, they can try it and change course. The overhead is not justified.

Skip it when urgency is genuine. An incident requires a decision in hours, not days. Use the RFC process post-incident to document what was decided, not to make the decision during one.

Skip it for implementation detail: design patterns inside a module, function structure, naming. These are code review territory. RFCs are for decisions that cross team boundaries or are hard to reverse.

Write an RFC when the decision affects multiple teams, when it is hard to reverse, or when you want a record of the reasoning that will outlast the people who made it.


The Real Value: Decisions That Outlast the Team

Engineers leave. Context leaks out of organizations continuously. The most common cause of re-litigating old decisions is that nobody can find a clear statement of why the original decision was made.

A well-maintained RFC archive is an organizational memory system. Six months from now, when a new engineer asks why the API is GraphQL instead of REST, the answer is a link, not a 30-minute conversation with whoever was in the room.

That is what a good RFC process delivers: not consensus, not perfect decisions, but documented reasoning that survives the people who produced it.

More in Engineering Management

The AI Productivity Paradox: Why Your Team Ships More Code but Delivers Less
Engineering Management ·

The AI Productivity Paradox: Why Your Team Ships More Code but Delivers Less

AI coding tools create an illusion of velocity at the individual level while degrading team-level delivery, quality, and maintainability. The core mechanism is a 5x+ senior/junior productivity split that aggregate metrics hide entirely.

The AI Productivity Paradox: Why Your Team Ships More Code but Delivers Less Value
Engineering Management ·

The AI Productivity Paradox: Why Your Team Ships More Code but Delivers Less Value

93% of developers use AI coding tools, yet DORA metrics haven't improved proportionally. Individual output rises while bug rates, review times, and deployment instability climb. Here is why individual AI productivity gains create organizational drag, and how to fix it with architecture-level guardrails.

Why Your Engineering Team Is Shipping Slower Than 6 Months Ago
Engineering Management ·

Why Your Engineering Team Is Shipping Slower Than 6 Months Ago

Engineering velocity declines at seed-to-Series-A startups for predictable, diagnosable reasons. Process debt, unclear ownership, hiring mistakes, burnout, and architectural bottlenecks all compound. Here is a diagnostic framework you can run in one afternoon, plus a tradeoffs table for each intervention.

The AI Ratchet Effect: Why Giving Your Engineering Team AI Tools Made Them Work Harder, Not Smarter
Engineering Management ·

The AI Ratchet Effect: Why Giving Your Engineering Team AI Tools Made Them Work Harder, Not Smarter

67% of engineers who adopted AI tools in 2025 worked more hours by year-end, not fewer. This is the AI ratchet effect: management converts every productivity gain into a permanently higher baseline. Here is how it happens, why it is worse at startups, and what a sustainable AI adoption cadence actually looks like.