Engineer Growth

How to Write a Technical Design Doc That Gets a Decision

Treat the document as a proposal for a decision—not a description of the solution you already want to build.

Published
Read time9 min read
A technical design document with a highlighted decision section and an orange approval stamp, illustrating a proposal designed to secure a clear decision.

A technical design doc helps a team decide what to build, why it matters, and which trade-offs to accept. It is not a place to document every implementation detail before the direction is agreed.

When a document gets no response, reviewers may not know what you need. When discussion jumps to minor implementation choices, the proposal may have described a solution before proving the problem. Write it as a decision proposal: lead with the question, support the problem with evidence, compare credible options, and state the decision required.

This guide offers a practical structure and a clearly hypothetical example. Adapt the depth to the change; this is not a universal company process.

What a technical design doc is for#

A technical design document is a proposal for a technical change. It gives affected people enough context to evaluate the problem, challenge assumptions, and decide before implementation creates expensive commitments.

A useful design doc supports three outcomes:

  • Alignment before code: expose missing requirements and disagreements while the design can still change.
  • A record of reasoning: preserve why an option was selected and which constraints mattered.
  • A decision mechanism: state what is being approved, who decides, and when.

A detailed design can still fail if it does not explain why the change is needed, which alternatives were considered, or what reviewers must approve.

Google's documentation guidance describes design docs and PRDs as documents used to collect feedback on a proposed implementation, then retained as archives of decisions after implementation. Google's Architecture Decision Records guidance separately describes capturing options, requirements, decisions, and reasons. These are public examples of useful practices, not a claim that every team follows the same process.

Start with the decision, not the solution#

Before writing the architecture section, complete this sentence:

We need a decision on whether to [specific choice] so that [intended outcome], by [date].

Then identify three things:

  1. What is being decided? State the actual choice: approve a migration, select a storage pattern, change an API boundary, introduce a queue, or keep the current design.
  2. Who decides? Name the decision owner or accountable group. Invite other people because they own affected systems, requirements, security, operations, or product constraints—not simply because they are senior.
  3. By when? Give reviewers a realistic deadline and explain the dependency. A date tied to a planned implementation milestone is more useful than an unexplained “ASAP.”

If you cannot answer these questions, do more discovery first. Do not ask reviewers to infer the decision from a long document.

Hypothetical example: An engineering team sees intermittent timeouts while generating monthly customer exports. The engineer proposes moving export generation to a background worker. The decision is not “review my worker architecture.” It is: “Should we move exports to an asynchronous job flow, or first optimize the existing request path? We need the backend lead and service owner to decide by 14 May so implementation can be planned for the next cycle.” The roles and date are illustrative, not a real team process.

The sections that make a design doc useful#

A design doc does not need a large template for every change. A small refactor may need a short proposal; a cross-service migration or security-sensitive change may need more context, diagrams, and operational detail. Include the sections that help reviewers evaluate the decision.

1. Context and problem: show what is happening#

Describe the current state and the problem that makes a change worth considering. Be specific about who or what is affected, when the issue occurs, and what happens if the team does nothing.

Use inspectable evidence: metrics with units and time windows, incident reports, support tickets, traces or logs, system constraints, and concrete user scenarios.

Avoid vague statements such as “the architecture does not scale.” Name the observed constraint, such as requests timing out when generation exceeds a deadline. Include counts or impact estimates only when your data supports them; label incomplete evidence clearly.

For the export example, attach timeout data, incident or ticket references, and the current request flow. If unavailable, label the failure pattern an initial report, not a confirmed trend.

2. Goals and non-goals: define the boundary#

Goals describe success. Prefer measurable outcomes with a known baseline: for example, a completion rate, processing-time target, latency budget, or reliability objective. Include the measurement window and source.

Do not invent targets because a template has a number-shaped blank. If the baseline is unknown, make baseline collection part of the proposal or label the target as an open decision.

Non-goals prevent scope creep. For the export example, goals might be completing long-running exports without holding an HTTP request open and exposing job status. Non-goals might include redesigning reporting or changing export formats.

3. Proposed design: explain the shape before the details#

Start with a system overview a reviewer can understand quickly. Describe the main components, their responsibilities, and the path of data or control between them. A simple diagram is often more useful than several paragraphs of component names.

For the hypothetical proposal, the overview could show:

  1. The client submits an export request.
  2. The API validates it and creates a job.
  3. A worker claims the job and generates the file.
  4. The result is stored and the job status is updated.
  5. The client checks status and retrieves the completed export.

Explain only decision-relevant details: job ownership, retries, idempotency, storage lifecycle, access control, failure handling, observability, and API changes. Move lower-level details to implementation tasks.

Use capacity estimates when scale changes the architecture. State assumptions such as request volume, payload size, processing duration, concurrency, retention, and expected growth. Show the calculation instead of dropping an unexplained number into the doc. The Letinix System Design Cheat Sheet can help organize estimation inputs and system building blocks; validate its reference figures against your own workload rather than treating them as service measurements.

4. Alternatives: include the simplest fix and doing nothing#

Do not explain only the preferred design. Show what else could solve the problem and why it may be less suitable.

At minimum, compare:

  • Do nothing: what happens if the team accepts the current behavior? Is the cost tolerable, or does the risk continue?
  • The simplest fix: could a timeout adjustment, query optimization, pagination, caching, or a bounded change solve the actual problem?
  • The proposed approach: what does it improve, and what complexity does it introduce?
  • Other credible options: include alternatives that meet the requirements and are realistic for the team to implement or operate.
OptionBenefitsCosts and risksWhen it may fit
Keep the synchronous flowNo new job infrastructureLong requests can still fail; request capacity remains occupiedImpact is low or the issue is temporary
Optimize the current pathSmallest architectural changeDoes not remove request-duration limits if work remains long-runningProfiling identifies a clear bottleneck
Use a background job flowSeparates request handling from long-running workAdds job state, retries, worker operations, and status handlingAsynchronous completion is a requirement

The table is illustrative. A real proposal should compare options that fit the actual system and evidence. Avoid straw-man alternatives that exist only to make the preferred solution look inevitable.

5. Risks, rollout, and rollback: explain how change stays controlled#

List specific failure modes and how the team will detect or contain them. Avoid generic labels such as “performance, security, and scalability.”

For a background export flow, ask whether duplicate job delivery can create duplicate exports, what happens when a worker crashes mid-file, whether users can access another customer's export, how stuck jobs are detected, how long completed files are retained, and what happens if the queue or storage is unavailable.

Describe a staged rollout. Identify the first cohort or traffic slice, the signals that determine whether rollout can continue, and who watches those signals. Define rollback in operational terms: which switch, deployment, or routing change returns the system to the previous behavior? What happens to jobs already in progress? A rollback plan that ignores partially processed work is incomplete.

For data migrations, include compatibility and recovery details. State whether old and new versions can run together, whether writes are reversible, and what data may need reconciliation. If rollback becomes unsafe after a particular step, identify that point explicitly.

Write for reviewers who skim#

Reviewers will scan before they read closely. Make the scan useful.

Write the summary last. Once the problem, goals, design, alternatives, and risks are stable, write a short summary containing the problem, proposed option, most important trade-off, requested decision, and deadline. Do not use it to introduce claims the body does not support.

Use headings that communicate the point. “Why large exports time out” is more informative than “Background.” A diagram should show the current or proposed flow, boundaries, and important failure paths—not decorative boxes. Tables help compare alternatives, requirements, and rollout criteria.

Cut anything that does not help the reviewer understand the problem, evaluate the options, or make the decision. Move detailed API contracts, field-by-field schemas, exhaustive test cases, and implementation tickets into linked supporting material when they are not central to the architecture choice. Keep the proposal focused; link to details rather than duplicating them.

Run the review as a process, not a broadcast#

A shared document link is not a review plan. Choose reviewers based on ownership and risk. Invite the decision owner, owners of affected systems and APIs, service operators, and relevant security, privacy, data, product, or support partners.

Ask reviewers to assess the areas they own: operations, authorization and data exposure, or user-facing behavior.

Use asynchronous comments for bounded proposals reviewers can assess independently. Set a deadline and ask focused questions. Meet when trade-offs remain unresolved, requirements conflict, or dependencies need joint discussion. The meeting should resolve issues, not replace the proposal.

End the review with a recorded outcome: accepted, rejected, deferred, or accepted with conditions. Capture the decision owner, date, rationale, unresolved conditions, and follow-up actions. Public engineering references show different ways to do this. Flutter's published RFC guidance describes asynchronous approval on the RFC pull request, with meetings used for discussion. GitLab's public architecture workflow recommends documenting context, benefits, trade-offs, alternatives, and the reason for the selected decision. Treat these as examples to adapt, not policies to assume at your company.

A short list of review questions#

Add questions that expose the uncertainties you need reviewers to address:

  • Is the problem supported by evidence, and is the impact described accurately?
  • Are the goals measurable and the non-goals clear?
  • Does the proposed design satisfy the stated requirements?
  • Have we compared the simplest fix and the option of doing nothing?
  • Which assumption, dependency, or failure mode could change the recommendation?
  • Can the change be rolled out gradually and rolled back safely?
  • Who owns the decision, and what must be true before implementation begins?

Avoid asking reviewers to “share any thoughts.” A specific question gives them a place to start and helps distinguish a blocking concern from a preference.

After approval: preserve the decision and update the design#

Approval is not the document's endpoint. Record the decision, rationale, and conditions. If implementation diverges, update the design or link to a follow-up record so it does not misdescribe the system.

Separate the proposal from the decision record when a choice deserves a durable, independently discoverable history. An Architecture Decision Record (ADR) can capture a specific architectural choice, its context, consequences, and alternatives. Google's public ADR overview describes recording options, requirements, the decision, and reasons, and retaining the history when a decision changes. GitLab's architecture workflow also describes using ADRs to record decisions and linking them from the main design document.

Do not silently overwrite the original reasoning when a decision changes. Record what changed, why the old decision no longer fits, and which new constraints or evidence drove the revision. Keep links between the proposal, decision record, implementation, and relevant operational documentation.

What to do next#

A strong design doc does not need to be long. It needs to make the problem legible, the options comparable, the risks visible, and the requested decision unmistakable.

If you are starting from a blank page, use the free Letinix Technical Design Doc Template. It gives you a structured starting point for presenting a system change, showing supporting evidence, and asking reviewers for a clear decision. Adapt the sections to the scope of your proposal rather than filling every heading mechanically.

References#

Muhammad Azlaan Zubair

Software Engineer and Researcher, writing about AI, developer tooling and automation.

Newsletter

New guides, comparisons and analysis, sent only when there is something worth your time.

  • New articles worth your time, not every link we publish.
  • Tools and resources when they launch.
  • No spam, no selling your address. Unsubscribe anytime.

Get useful signal by email

We're building the list before the first issue. You'll get an email when the newsletter starts.