../

System design

Prompting for distributed-systems design: turning a product idea into requirements, capacity estimates, APIs, data models, storage, caching, queues, consistency choices, scaling and failure plans, observability and cost, and using an assistant for design reviews and interview practice. Written for someone who has never designed a system that runs on many machines. The concepts are explained in System design concepts, the numbers and production tables in System design, the interview format in System design interviews; code-level structure is in Software architecture and the method behind every prompt in Prompting fundamentals.

How experts think

A system designer works from requirements to numbers to structure, and only then to technology. The usual sequence (the same one interviewers expect):

StepQuestionAsk the model
1. Functional requirementswhat must it do? 3–5 core use cases; what is out of scope"List the core use cases and propose what to leave out of version 1."
2. Non-functional requirementshow fast, how available, how consistent, how durable, how cheap, where"Turn 'fast and reliable' into numbers: p99 latency, availability, durability, consistency per operation."
3. Estimatesrequests per second (average and peak), storage per year, bandwidth, read:write ratio"Estimate QPS, storage and bandwidth step by step with units."
4. APIwhat the clients call, with request and response shapes"Define the API: endpoints, payloads, pagination, idempotency, errors."
5. Data modelentities, access patterns, keys, indexes; then the store"List the access patterns first, then choose a store that serves them."
6. High-level designthe boxes and the read and write paths through them"Draw the read path and the write path separately."
7. Deep divesthe 2–3 hardest parts: hot keys, fan-out, consistency, a failure"Which 3 parts of this design are hardest? Go deep on each."
8. Trade-offs and evolutionwhat breaks at 10x, what you would monitor, what you rejected"What breaks first at 10x traffic, and what would you change?"

Step 6 on a typical web architecture, with one read and one write walked through it hop by hop:

on a cache miss sync async read path: GET /feed 1 CDN: serves images itself; the feed call passes through 2 load balancer: picks any healthy app server 3 app server: holds no session, so any one can answer 4 cache: miss (on a hit, most reads end right here) 5 replica: the app reads the feed rows 6 cache: the app stores the result with a TTL 7 the response goes back the way it came 8 reads never touch the primary write path: POST /photos 1 CDN: passes writes through to the origin 2 load balancer: picks any healthy app server 3 app server: validates the upload 4 primary: the row commits; the only node that takes writes 5 async: replicas copy the change; a thumbnail job is queued 6 worker: takes the job and makes the thumbnails 7 until replication catches up, a replica read can be stale 8 the write path is short; consistency matters most here client browser CDN edge cache LB any server app ×3 stateless primary Postgres replicas read-only cache Redis queue jobs workers thumbnails

Reads spread across caches and replicas; every write goes through the one primary, and the rest happens after it.

Habits behind the steps:

  • Numbers decide. A design for 50 requests per second and one for 50,000 look nothing alike; estimate before choosing.
  • Access patterns pick the database, not fashion: know the top queries and their keys before naming a store.
  • Design for peak, typically 2–10x the average, and for the failure of any single part.
  • Consistency is chosen per operation: a payment needs it strong, a like count can be eventual.
  • Find the bottleneck: the one resource that saturates first (database writes, a hot key, network egress).
  • Everything fails: machines, zones, dependencies, deploys. Ask what happens when each part is slow, not just down.
  • Simplicity is a feature: one well-run Postgres with replicas covers more scale than most products reach.
  • Cost is a requirement: a design that meets every SLO at ten times the budget has failed.

Vocabulary

TermWhat it meansSay it like
Functional requirementsomething the system does: post, follow, search"Functional: create short links, redirect, show click counts."
Non-functional requirementa quality it must have: latency, availability, durability, cost"Non-functional: redirects p99 under 50 ms, 99.99% available."
Latency percentile (p50, p95, p99)the time under which 50%, 95% or 99% of requests finish; p99 shows the slow tail"Target p99, not the average."
Throughput / QPSrequests (or queries) handled per second"Estimate average and peak QPS for reads and writes separately."
Back-of-the-envelope estimatea quick order-of-magnitude calculation with rounded numbers"Do a back-of-the-envelope estimate, showing units at every step."
Read:write ratiohow many reads per write; drives caching and storage choices"Assume a 100:1 read:write ratio unless I say otherwise."
Access patterna specific way data is read or written: by which key, how often, how much"List the access patterns before proposing tables."
SLI / SLO / SLAservice level indicator (a measurement), objective (the target for it), agreement (a contract with penalties)"Define SLIs and SLOs for the redirect path; no SLA."
Error budgetthe failure an SLO allows (99.9% leaves 0.1%), spent on releases and incidents"Explain how the error budget limits release speed."
Availability nines99.9% ≈ 43 minutes of downtime per 30 days; 99.99% ≈ 4.3 minutes"Is three nines enough here, given the cost of four?"
Vertical / horizontal scalinga bigger machine / more machines"Scale vertically until it stops being cheaper, then horizontally."
Stateless servicekeeps no client state between requests, so any instance can serve any request"Keep the API tier stateless behind the load balancer."
Load balancer (L4 / L7)spreads requests across instances; L4 by connection, L7 by HTTP content"Put an L7 load balancer in front, routing by path."
Cache (cache-aside, TTL, hit rate)a fast copy of hot data; the app checks the cache, falls back to the database, then fills the cache; entries expire after a time to live"Cache-aside in Redis, 5-minute TTL, delete the key on update; target 90% hit rate."
CDNcontent delivery network: servers near users that cache static and cacheable responses"Serve images and static assets through a CDN."
Replicationcopies of data on several nodes; leader-follower is the usual form"One leader, two read replicas; reads that must be fresh go to the leader."
Sharding / partition keysplitting data across nodes by a key"Shard by user ID; check for hot partitions."
Hot key / hot partitionone key or shard getting far more traffic than the rest"How do we handle a celebrity account as a hot key?"
Strong vs eventual consistencyevery read sees the latest write / reads may be stale for a while"Strong for balances, eventual for counters."
CAP and PACELCunder a network partition choose consistency or availability; else trade latency against consistency"Using PACELC, what does this store choose with and without a partition?"
Quoruma read or write must reach a majority (or R and W replicas with R + W > N)"Explain the quorum settings and what they guarantee."
Idempotencydoing an operation twice has the same effect as once; an idempotency key lets clients retry safely"Require an idempotency key on payment creation."
Message queue / loga buffer between producers and consumers (SQS, RabbitMQ) or a durable, replayable event log (Kafka)"Put a queue between upload and thumbnail generation."
At-least-once deliverymessages may arrive more than once; consumers must be idempotent"Assume at-least-once delivery and make consumers idempotent."
Backpressure / load sheddingslowing producers / rejecting excess work to stay up under overload"Shed low-priority traffic first when the queue passes N."
Rate limitingcapping requests per client per time window (token bucket, sliding window)"Rate limit link creation per user with a token bucket."
Timeout, retry with backoff and jittergive up after a set time; retry after growing, randomized delays"Timeouts on every call; retries only for idempotent requests, with full jitter."
Circuit breakerstops calling a failing dependency for a while so it can recover"Wrap the recommendation service in a circuit breaker with a fallback."
Single point of failure (SPOF)a part whose failure takes the system down"List every single point of failure."
Failoverswitching to a standby when the primary fails"How long does database failover take, and what is lost?"
RPO / RTOrecovery point objective (data loss allowed) / recovery time objective (downtime allowed)"RPO 5 minutes, RTO 1 hour for the region-loss scenario."
Fan-out on write / on readprecompute each follower's feed at post time / assemble it when read"Hybrid fan-out: on write for most users, on read for accounts with millions of followers."
Denormalizationstoring duplicated data to make reads cheap"Denormalize the author name into the post for feed reads."
Transactional outboxwriting an event to an outbox table in the same transaction as the data, then publishing it"Use an outbox so the event is published exactly when the order commits."
Sagaa multi-service workflow of local transactions with compensating steps on failure"Model checkout as a saga with compensations."
Observabilitymetrics, logs and traces that explain behavior from outside"Give the observability plan: golden signals, traces across services, structured logs."
Golden signalslatency, traffic, errors and saturation: the four metrics Google's SRE book says to watch on any user-facing system"Show the four golden signals for the feed service."
RED methodfor every service, watch request rate, errors and duration (Tom Wilkie's method for request-driven services)"One RED dashboard per service."
USE methodfor every resource (CPU, memory, disk, network, a queue, a connection pool), check utilization, saturation and errors (Brendan Gregg's method)"Run the USE method over the database host and the worker queue."
Unit costcost per request, per user or per GB"Estimate monthly cost and cost per 1,000 requests."

Availability numbers combine in a way that surprises people:

In series: every part must be up, so availabilities multiply CDN 99.9% LB 99.9% app 99.9% cache 99.9% DB 99.9% ≈ 99.5% end to end 0.999 × 0.999 × 0.999 × 0.999 × 0.999 ≈ 0.995 ≈ 3.6 hours of downtime per 30 days, not the 43 minutes of one part In parallel: one copy is enough, so failure chances multiply request replica, zone A 99.9% replica, zone B 99.9% ≈ 99.9999% at least one up 1 − 0.001 × 0.001 ≈ 3 seconds per 30 days only if failures are independent: a shared zone, deploy or bug takes both down
Serial dependencies multiply availability down; redundant copies multiply the failure chance down.

Capacity estimates

Estimates are orders of magnitude, used to choose between designs. The formulas (more in System design):

QPS average  = daily actions / 86,400 s
QPS peak     ≈ QPS average × peak factor (2-10, often 3)
Storage/year = writes/day × bytes per write × 365
               × replication factor (plus index overhead)
Bandwidth    = QPS × bytes per response   (× 8 for bits/s)
Servers = peak QPS / (QPS per server × target utilization)
Concurrency  = arrival rate × latency      (Little's law)
 
1 million requests/day ≈ 12 per second
1 billion requests/day ≈ 12,000 per second

Worked check, with the photo-sharing inputs from Brief the model: 5M users × 50 views = 250M reads/day ÷ 86,400 ≈ 2,900 reads/s, ≈ 8,700/s at a 3x peak. Uploads: 5M × 0.2 = 1M/day ≈ 12/s. Storage: 1M × 2 MB = 2 TB/day ≈ 730 TB/year of originals before replication. Egress at peak: 8,700/s × 200 KB ≈ 1.7 GB/s ≈ 14 Gbit/s.

Reads: home-feed views 5M daily users 250M feed views/day ≈ 2,900/s average reads × 50 views ÷ 86,400 s × 3 peak ≈ 8,700/s peak reads ≈ 1.7 GB/s peak egress ≈ 14 Gbit/s on the wire × 200 KB × 8 bits → cache + replicas → serve from a CDN Writes: photo uploads 5M daily users 1M uploads/day ≈ 12/s average writes × 0.2 ÷ 86,400 s → one primary copes × 2 MB 2 TB new photos/day ≈ 730 TB per year, 1 copy × 365 → object storage check: 1M/day ≈ 12 per second
Every estimate should end in a decision; units on every arrow make the slips visible.
Common errorExampleCatch it by
Wrong time unitdividing by 3,600 (seconds per hour) instead of 86,400 (per day)1M/day must come out near 12/s
Bits vs bytes1.7 GB/s reported as 1.7 Gbit/s, 8x too lowunits on every line; network links are sold in bits
Lost power of ten250M ÷ 86,400 written as 29,000round first: 2.5 × 10^8 ÷ 10^5 ≈ 2,500
Forgotten peakservers sized for average trafficask for average and peak in separate columns
Forgotten copiesstorage without replicas, indexes, backupsask what multiplies the raw size
Unused estimatenumbers computed, then ignored"Which design decisions did these numbers change?"

Failure-mode analysis

Ask for failures per component in a fixed table so nothing hides in prose. Failure mode and effects analysis (FMEA) is the engineering name for this kind of table. Classic FMEA also rates each row's severity, occurrence and detection from 1 to 10 and multiplies them into a risk priority number (RPN) to rank the rows; for a software design, ranking by likelihood and impact is often enough.

ComponentFailure modeDetectionUser impactMitigationRecovery
Redis cachenode lostcache error rate, hit-rate dropslower feeds; database load spikesreplicas; request coalescing; rate limit refillsautomatic failover; warm the cache gradually
Postgres primarycrashhealth check, replication lag alertwrites fail for the failover timesynchronous standby in another zoneautomated failover; check for lost writes
Thumbnail workerpoison messageretries exceed limitsome photos lack thumbnailsdead-letter queue after N attemptsfix, then replay the dead-letter queue
Payment providerslow, not downp99 latency of outbound callscheckouts hangtimeout, circuit breaker, queue the captureretry idempotently when it recovers

Failure modes to make the model consider (it usually lists only "server crashes"): a dependency that is slow rather than down, zone and region outages, network partitions, a bad deploy or config change, retry storms, cache stampedes (many requests rebuilding the same entry at once), hot partitions, poison messages, full disks, expired certificates, DNS failures, clock skew, provider quotas and rate limits, and silent data corruption.

client browser CDN edge cache LB any server app ×3 stateless primary Postgres replicas read-only cache Redis 3rd party payments queue jobs workers thumbnails 1 1 zone outage: every tier in 2+ zones 2 2 bad deploy: canary, fast rollback 3 3 cache lost: coalesce, refill slowly 4 4 primary crash: standby in another zone 5 5 replica lag: fresh reads from primary 6 6 poison message: dead-letter queue 7 7 slow API: timeout, circuit breaker 8 8 retry storm: backoff with jitter each part fails; the fix belongs in the design
Ask for a failure mode on every box and arrow, then check each fix is in the design.

Brief the model

Each input has a slot in the skeleton; the last column says which.

InputWhy it mattersExampleSlot
Product and core use casesscope decides everything"Photo sharing: upload, follow, home feed, likes. No messaging, no stories."<context>
Users and behaviorthe basis of every estimate"5M daily active users; each views ~50 photos and uploads ~0.2 per day."<context>
Peak patterndesign for peak, not average"Evening peak ≈ 3x average; launch days 10x."<context>
Data sizes and retentionstorage and bandwidth"Photos ~2 MB original, ~200 KB feed size; keep forever."<context>
Latency targetswhich paths need caching or precomputation"Feed p99 under 300 ms; upload can take seconds."<requirements>
Availability and durabilityredundancy level and cost"Feed 99.9%; uploaded photos must never be lost."<requirements>
Consistency per operationwhere strong guarantees are needed"Likes may lag; a deleted photo must disappear everywhere within a minute."<requirements>
Geographyregions, latency, data residency"Users in the EU and US; EU data stays in the EU."<requirements>
Existing stack and constraintsstops it designing for a stack you don't run"AWS, Postgres, Redis, TypeScript; no Kubernetes."<context> (the stack), <requirements> (the must-nots)
Team and operationswhat you can actually run at 3 a.m."4 engineers, shared on-call."<context>
Budgetrules out over-built designs"Infrastructure under $5,000/month at launch."<requirements>
Purpose of the exerciseproduction design vs interview practice need different depth"Production design doc for a review next week."<task>
Existing design, diagrams, incident notesa redesign starts from what existspaste them<materials>

What to ask for

StageDeliverableAsk for it like
Requirementsrequirements list"Functional, non-functional (with numbers) and out of scope, as three lists."
clarifying questions"The 8 questions a senior engineer would ask before designing this."
SLO table"SLIs and SLOs per user journey, with the error budget per 30 days."
Estimatecapacity estimate"A table: quantity, formula, inputs, result, units, for QPS, storage, bandwidth, cache size and server count."
InterfaceAPI spec"Endpoints with request and response JSON, pagination, idempotency keys, error codes; or an OpenAPI sketch."
event schemas"The events on the queue, with fields, keys and versioning."
Dataaccess patterns table"Each query: key, frequency, latency target, consistency."
data model"Tables or documents with keys and indexes that serve those patterns."
storage choice"Compare 3 stores for this workload against the access patterns."
Architecturehigh-level diagram"A Mermaid flowchart of components; label every arrow with what flows."
read and write paths"A Mermaid sequence diagram for the read path and one for the write path."
Deep divescaching plan"What to cache, where, key format, TTL, invalidation, stampede protection."
consistency table"Each operation, the consistency it needs, how the design provides it."
scaling plan"What breaks at 10x and 100x, in order, and the fix for each."
Reliabilityfailure-mode analysis"Failure modes per component: detection, impact, mitigation, recovery."
disaster recovery plan"Backups, restore drills, RPO and RTO per data store."
load-test plan"Scenarios, target rates, pass criteria."
Operateobservability plan"Golden signals per service, traces, dashboards, burn-rate alerts."
cost estimate"Monthly cost by component with assumptions, and cost per 1,000 requests."
rollout plan"Phases, feature flags, migration steps, rollback."
Decidedesign doc and review"A design doc: context, goals, non-goals, design, alternatives, risks, open questions."

The prompt chain

The chain's deliverable is a design document for a distributed system: requirements with SLOs, capacity estimates, API and data model, the architecture with its read and write paths, a failure-mode analysis, and the observability and cost plans. Run the four stages in order; each prompt uses the skeleton and names the standards a staff engineer would apply (SLOs and error budgets, FMEA, the RED and USE methods) instead of asking the model to play one.

1. Interview

Use first, while all you have is a one-line idea: the numbers you don't have yet decide the design.

<context>
I want to build [system, e.g. a photo-sharing
app: upload, follow, home feed, likes]. It's for
[purpose: design doc | design review | interview practice].
What exists: [current state, e.g. nothing yet;
an AWS account, 4 engineers who know Postgres].
I have never designed a system that runs on many machines.
</context>
 
<task>
Interview me before designing anything. The end result
will be a design document (requirements, estimates,
API, data model, architecture, failure-mode analysis);
first you need the requirements and the numbers.
</task>
 
<requirements>
- At most 10 questions, grouped under: scope and
  use cases; users and load; latency, availability
  and durability targets; consistency per
  operation; data size and retention; geography and
  residency; stack, team and operations; budget.
- For each question: one line on how the
  answer changes the design, and 2–3 typical
  answers, with numbers, I can pick from.
- No architecture, technologies or estimates yet.
</requirements>
 
<quality_bar>
Before answering, check your questions against:
- Each answer would change a number or a
  component; drop any question that wouldn't.
- Targets are asked for as SLOs with
  percentiles and percentages, not adjectives.
- Consistency is asked per operation,
  not once for the whole system.
</quality_bar>
 
<output_format>
Numbered questions under the
group headings, and nothing else.
</output_format>
 
<process>
Ask all the questions in one message, then stop.
When I answer, write the requirements back as
functional, non-functional (with numbers) and out
of scope, mark anything still open [NEEDS SOURCE],
and end with a list of the assumptions you made.
</process>

2. Options

Use once the requirements have numbers: left alone, the model recites one memorized "standard design"; you want the real alternatives, each tied to the estimate.

<materials>
[paste the requirements from stage 1, with my answers]
</materials>
 
<context>
Team and operations: [team, e.g. 4 engineers, shared
on-call, no Kubernetes experience]. Budget: [budget, e.g.
under $5,000/month at launch]. The decision I'm least sure
about: [open question, e.g. how to build the home feed].
</context>
 
<task>
High-level design options for this system, so I
can choose one before the full design document.
</task>
 
<requirements>
- First a back-of-the-envelope estimate: average and peak
  QPS for reads and writes, storage per year, egress,
  with units at every step. Every option must cite it.
- 2–4 materially different options, differing in data
  store, fan-out or consistency on the key operation; one
  must be the simplest design that meets the numbers.
- For each: the read and write paths, what saturates first,
  how it meets each SLO, the monthly cost drivers, the
  operational load for this team, and what breaks at 10x.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing;
  mark cloud prices and quotas [VERIFY].
</requirements>
 
<quality_bar>
Before answering, check your draft against:
- The arithmetic is right: 1 million
  requests a day is about 12 per second.
- Every component is justified by a
  number from the estimate or by an SLO.
- Each option names its bottleneck
  and its single points of failure.
- The recommendation says what would
  make you choose differently.
</quality_bar>
 
<output_format>
The estimate table (quantity | formula | inputs |
result | units); one section per option with a
Mermaid flowchart; a comparison table (option |
meets SLOs? | bottleneck | cost drivers | ops load |
breaks at 10x); a recommendation in under 100 words.
</output_format>
 
<process>
End with a list of the assumptions you
made. Then stop and wait for my choice: no
API, data model or failure analysis yet.
</process>

3. Produce

Use after you have chosen: the full design document for one option, in the form reviewers approve.

<materials>
[paste the requirements from stage 1]
[paste the chosen option, the estimate
table and the comparison from stage 2]
</materials>
 
<context>
[product and purpose, e.g. photo sharing; a production
design doc for review next week]. Stack: [stack, e.g.
AWS, Postgres, Redis, TypeScript; no Kubernetes]. Team:
[team, e.g. 4 engineers, shared on-call]. Reviewers:
[reviewers, e.g. two senior engineers and the CTO].
We chose [option, e.g. one Postgres primary with
read replicas, Redis cache-aside, a queue for
thumbnails] because [reason, e.g. it meets the SLOs
at a third of the cost of the sharded option].
</context>
 
<task>
The design document for the chosen option: what
the reviewers approve and the team builds from.
</task>
 
<requirements>
- SLOs per user journey, each with an SLI and
  a 30-day error budget; availability at
  [availability: 99.9% | 99.95% | 99.99%],
  justified by what the next nine would cost.
- Capacity estimates as a table with formula and units,
  average and peak; every major choice cites a number.
- Access patterns before the data model; consistency
  chosen per operation (strong, read-your-writes or
  eventual), with how the design provides each. [key
  operation, e.g. deleting a photo] needs
  [consistency: strong | read-your-writes | eventual].
- A failure-mode analysis in FMEA form for every component
  and arrow, slow-not-down dependencies included.
- Observability: RED metrics for every service, USE metrics
  for every resource, burn-rate alerts on the SLOs.
- Timeouts on every remote call; retries only on
  idempotent operations, with backoff and jitter.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing;
  mark cloud prices and quotas [VERIFY].
</requirements>
 
<quality_bar>
Before answering, check your draft against:
- Every estimate recomputed a second
  way, with units on every line.
- Each SLI can be measured from
  metrics the design actually emits.
- No single point of failure without
  a stated reason to accept it.
- Every queue, cache and fan-out has a
  bound and a plan for when it fills.
- The monthly cost fits the budget.
</quality_bar>
 
<output_format>
Markdown, under [length, e.g. 6 pages], in these sections:
context, goals and non-goals; requirements and SLOs;
capacity estimates; API; access patterns and data model;
architecture (a Mermaid flowchart, and sequence diagrams
for the read and write paths); deep dives on the 3 hardest
parts; consistency table; failure-mode analysis (component
| failure mode | detection | user impact | mitigation |
recovery); observability and alerts; cost; rollout and
rollback; alternatives considered; open questions.
</output_format>
 
<process>
Ask me up to 3 questions first if anything
missing would change your answer; otherwise go
on. End with a list of the assumptions you made.
</process>

4. Review

Run this in a fresh chat, pasting only the design document and the requirements. A model reviewing its own draft shares its blind spots (the same arithmetic slip, the same forgotten failure), so the critique has to come from a chat that didn't write it; before production, a person who will be on call for it should review it too.

<materials>
<design>
[paste the design document]
</design>
<brief>
[paste the requirements and SLOs]
</brief>
</materials>
 
<context>
This is a fresh chat: you did not write this design.
It goes to review [when, e.g. on Thursday], where the
reviewers approve it, ask for changes or reject it.
</context>
 
<task>
A review of the design document before approval: what would
make it miss its SLOs, its budget or its operability.
</task>
 
<requirements>
- Check each requirement and SLO: met,
  unclear or not met, with the evidence.
- Recompute the estimates' arithmetic.
- Find single points of failure, unbounded
  resources (queues, caches, fan-out) and
  remote calls without timeouts.
- Check that the failure-mode analysis covers
  slow-not-down dependencies, zone loss, bad
  deploys, retry storms and hot keys.
- Score 1–5 on: requirements, estimates, estimates
  used, API, data model, storage choice,
  bottlenecks, consistency, failure handling,
  operations, cost, trade-offs, simplicity.
- Do not rewrite the design and do not praise it.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing.
</requirements>
 
<quality_bar>
Before answering, check your review against:
- Every problem cites the section or number it comes from.
- Problems are ranked by user impact
  times likelihood, worst first.
- Each fix says what it costs: money, latency or complexity.
- If you found fewer than 5 problems,
  you say which checks came back clean.
</quality_bar>
 
<output_format>
A requirements check table; arithmetic corrections; the
scorecard; the ranked fixes (problem | evidence | fix |
cost); the questions the author must answer before approval.
</output_format>
 
<process>
End with a list of the assumptions you made.
</process>

Take the top fixes back to the chat that wrote the design: "Apply fixes 1–3, keep everything else, list what you changed." If a fix changed the estimates, rerun stage 4 in another fresh chat.

Goals and loops

In an agent that runs commands and checks its own work, such as Claude Code, the Produce stage can run until it measurably passes: /goal keeps starting turns until a condition holds, and /loop repeats a prompt or skill on an interval. The checker reads only the conversation, so every condition below names a check whose output Claude prints, the constraints that must survive, and a bound. How to write your own: Goals and loops.

TaskCompletion condition
Capacity estimate/goal python estimate.py prints peak QPS, storage per year and egress bandwidth, and each matches the design doc's hand calculation within 1% (show both); or stop after 10 turns
Load test the design's hot path/goal k6 run load.js shows p95 latency under 300 ms and an error rate under 0.1% at the target request rate, quoted from its summary; no endpoint removed from the script; or stop after 20 turns
Complete the design document/goal design.md has every section of the template, every SLO has a number and an alert, and every component in the diagram has a row in the failure-mode table (print mismatches: none); or stop after 10 turns

Loops that fit: during a rollout, /loop 10m to read the canary's error rate and latency (through your monitoring's MCP server) and report a rollback recommendation the moment a threshold is crossed, without rolling back itself.

What a checker can't judge: whether the design is right for the requirements and the team that will run it. Review it in a fresh chat and with an engineer who has operated something similar.

Prompt library

One entry per deliverable from What to ask for, outside the chain. Quick is the minimum that still works; Full is the skeleton filled in. Replace each placeholder: pick one option, or write your own value.

Capacity estimate

Stage: produce · Use when: you need numbers you can trust enough to choose a design with.

Quick

Estimate capacity for [system, e.g. a URL shortener] from
[inputs, e.g. 10M DAU, 5 actions/user/day, 1 KB per item,
kept 5 years, 3x peak]: a table (quantity | formula | inputs
| result | units) for average and peak QPS, storage per year
and egress. Check it by recomputing each line with code.

Full

<context>
System: [system, e.g. photo sharing with a home feed].
Users: [daily active users, e.g. 5M]. Behavior: [actions per
user per day, e.g. 50 feed views and 0.2 uploads]. Sizes:
[item sizes, e.g. 2 MB original, 200 KB feed size].
Retention: [retention, e.g. forever]. Peak:
[peak factor: 2x | 3x | 10x]. Copies: [replication, e.g. 3].
The estimate decides [decision, e.g. whether one
Postgres primary is enough and whether we need a CDN].
</context>
 
<task>
A back-of-the-envelope capacity estimate,
used to choose between designs.
</task>
 
<requirements>
- Average and peak QPS for reads and writes separately;
  storage per day and per year, with replication and index
  overhead; egress in bytes/s and bits/s; cache memory for
  the hot set; server count at 60% utilization.
- Units at every step; round to 2 significant figures.
- Per-server throughput is an assumption: state
  it and mark it [VERIFY] with a load test.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing.
</requirements>
 
<quality_bar>
Before answering, check your draft against:
- Per-day figures are divided by 86,400: 1M
  a day must come out near 12 per second.
- Bits and bytes are labeled;
  network figures are given in bits.
- Peak and average are separate columns.
- Every result ends in the design decision it supports.
</quality_bar>
 
<output_format>
A table: quantity | formula | inputs | result | units.
Then one line per result: the decision it changes.
</output_format>
 
<process>
Recompute every line a second way (or by running
code) and flag any line where the two differ.
End with a list of the assumptions you made.
</process>

API specification

Stage: produce · Use when: the requirements are agreed and you need the interface clients will call.

Quick

Define the API for these use cases: [paste use
cases]. Endpoints with request and response JSON,
cursor pagination, idempotency keys on writes and
error codes. Check every use case maps to an
endpoint and every write can be retried safely.

Full

<materials>
[paste the functional requirements and use cases]
</materials>
 
<context>
Clients: [clients, e.g. a web app and an iOS
app; third-party integrations next year]. Style:
[API style: REST with JSON | gRPC | GraphQL].
</context>
 
<task>
An API specification for these use cases,
reviewable before anyone writes code.
</task>
 
<requirements>
- Each endpoint: method and path, request
  and response JSON, status and error codes.
- Pagination: [pagination: cursor | offset],
  with a page-size limit.
- Every write that isn't naturally
  idempotent accepts an idempotency key.
- Versioning and rate limits stated.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing.
</requirements>
 
<quality_bar>
Before answering, check your draft against:
- Every use case maps to at least one
  endpoint, and every endpoint to a use case.
- A client that retries any write after
  a timeout cannot create a duplicate.
- Each error response tells the
  client whether retrying can help.
</quality_bar>
 
<output_format>
A table (method | path | purpose | idempotent?),
then each endpoint's request and response as
JSON, or an OpenAPI 3 sketch in YAML.
</output_format>
 
<process>
Ask me up to 3 questions first if anything
missing would change your answer; otherwise go
on. End with a list of the assumptions you made.
</process>

Storage choice

Stage: options · Use when: several data stores sound plausible and you can't tell them apart.

Quick

List the access patterns for [system, e.g. a chat app]
(query | key | frequency | latency target | consistency),
compare 3 stores against them and recommend one. Default
to Postgres unless a pattern rules it out, and check that
every pattern is served by a key or index in your pick.

Full

<materials>
[paste the access patterns, or the use
cases if you have no patterns yet]
</materials>
 
<context>
Data now and in 3 years: [data size, e.g. 200 GB
now, 5 TB in 3 years]. Team: [team, e.g. 4 engineers
who already run Postgres]. Cloud: [cloud, e.g. AWS].
</context>
 
<task>
A comparison of data stores for
this workload, so I can choose one.
</task>
 
<requirements>
- Start from the access patterns: query, key,
  frequency, latency target, consistency.
- Compare
  [stores: Postgres | DynamoDB | Cassandra | MongoDB] on fit
  to each pattern, consistency options, the scaling limit
  for this workload, operational burden and cost drivers.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing;
  mark vendor limits and prices [VERIFY].
</requirements>
 
<quality_bar>
Before answering, check your draft against:
- Every access pattern is served by a
  key or index in the recommended store.
- The scaling limit is stated for
  this workload, not in general.
- The operational burden counts what this team already runs.
</quality_bar>
 
<output_format>
An access-patterns table; a comparison table (store
| each pattern | consistency | scaling limit | ops
burden | cost drivers); a recommendation, and the
change in workload that would make you switch.
</output_format>
 
<process>
End with a list of the assumptions you
made. Then stop: no schema until I choose.
</process>

Caching plan

Stage: produce · Use when: reads are slow or the database is overloaded.

Quick

For [system, e.g. a product catalog] with [load, e.g. 5,000
reads/s, 100:1 read:write, 50 GB data], design caching:
what, where, key format, TTL, invalidation on write,
stampede protection, hit rate and hot-set memory (show the
arithmetic). Check what happens when the cache is empty.

Full

<materials>
[paste the access patterns and the current read path]
</materials>
 
<context>
Load: [load, e.g. 5,000 reads/s at peak, 100:1
read:write]. Data: [data, e.g. 50 GB; 10% of items get
90% of reads]. Freshness: [staleness allowed, e.g.
prices within 1 minute, descriptions within 1 hour].
</context>
 
<task>
A caching plan for this read path.
</task>
 
<requirements>
- Pattern:
  [pattern: cache-aside | read-through | write-through],
  and the layer for each item: CDN, app memory or Redis.
- Key format, TTL and invalidation
  on write for each cached item.
- Stampede protection (request coalescing or a lock)
  and the behavior when the cache is cold or lost.
- Expected hit rate and hot-set memory, with the arithmetic.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing.
</requirements>
 
<quality_bar>
Before answering, check your draft against:
- Every cached item has a TTL and an invalidation
  path that meet its freshness limit.
- Losing the cache doesn't send the full
  read load to the database at once.
- The memory figure follows from
  the item size and the hot set.
</quality_bar>
 
<output_format>
A table: item | layer | key format | TTL |
invalidation | staleness allowed. Then the hit-rate
and memory arithmetic, then the cold-cache plan.
</output_format>
 
<process>
End with a list of the assumptions you made.
</process>

SLOs and observability

Stage: produce · Use when: a service is going to production and nobody has defined "working".

Quick

For these user journeys: [paste journeys], define
SLIs, SLOs and the 30-day error budget, then RED
metrics per service, USE metrics per resource, and
multiwindow burn-rate alerts. Check each SLI can
be measured from metrics we would actually have.

Full

<materials>
[paste the component list or architecture
diagram, and the user journeys]
</materials>
 
<context>
On-call: [on-call, e.g. 4 engineers, a week each,
business hours only]. Tooling: [tooling, e.g.
Prometheus and Grafana, OpenTelemetry traces].
</context>
 
<task>
An SLO and observability plan for this system.
</task>
 
<requirements>
- Per user journey: the SLI, an SLO at
  [availability: 99.9% | 99.95% | 99.99%] or a latency
  percentile, and the 30-day error budget in minutes.
- Dashboards by the RED method for every service
  (rate, errors, duration) and the USE method for
  every resource (utilization, saturation, errors).
- Multiwindow, multi-burn-rate alerts on each
  SLO, as in the Google SRE workbook; say
  which page someone and which open a ticket.
- Traces across service boundaries;
  structured logs carrying a request ID.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing.
</requirements>
 
<quality_bar>
Before answering, check your draft against:
- Every SLI is a ratio of good events to valid
  events, measurable from the listed metrics.
- Pages fire on symptoms (the SLO
  burning), not on causes (CPU high).
- The budget arithmetic is right: 99.9%
  over 30 days leaves about 43 minutes.
</quality_bar>
 
<output_format>
An SLO table (journey | SLI | SLO | error budget per 30
days); a dashboard list (service or resource | metrics); an
alert table (alert | windows | burn rate | page or ticket).
</output_format>
 
<process>
Ask me up to 3 questions first if anything
missing would change your answer; otherwise go
on. End with a list of the assumptions you made.
</process>

Cost estimate

Stage: produce · Use when: you need a monthly figure before committing to a design.

Quick

Estimate the monthly cost of this design by component,
and the cost per 1,000 requests: [paste design and
capacity estimate]. Show quantity × unit price per line.
Check no price is quoted from memory as fact: mark every
unit price [VERIFY] with the pricing page to check.

Full

<materials>
[paste the design and the capacity estimate]
</materials>
 
<context>
Cloud and region: [cloud and region, e.g.
AWS eu-west-1]. Budget: [budget, e.g.
under $5,000/month at launch]. Pricing:
[pricing: on-demand | savings plans | spot for workers].
</context>
 
<task>
A monthly cost estimate for this design, to
compare with the budget and find the cost drivers.
</task>
 
<requirements>
- Cost by component: compute, storage, database,
  cache, egress, queues, observability.
- Each line: a quantity from the
  capacity estimate times a unit price.
- Mark every unit price [VERIFY] with
  the pricing page to check it on.
- Cost per 1,000 requests and per active user.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing.
</requirements>
 
<quality_bar>
Before answering, check your draft against:
- Every quantity traces to the capacity estimate.
- Egress is included; it is the
  line people most often forget.
- The 3 biggest drivers are named, each
  with one change that would cut it.
</quality_bar>
 
<output_format>
A table: component | quantity | unit price |
monthly cost | assumption. Then the totals,
the unit costs and the top 3 drivers.
</output_format>
 
<process>
End with a list of the assumptions you made.
</process>

Failure-mode analysis

Stage: review · Use when: a design is about to be approved and its failure handling is one sentence long.

Quick

For this design: [paste design], write an FMEA-style
table (component | failure mode | detection | user impact
| mitigation | recovery) covering slow-not-down
dependencies, zone loss, bad deploys, retry storms, cache
stampedes, hot partitions and poison messages. Check
every box and arrow has a row; mark missing mitigations.

Full

<materials>
[paste the design document and diagrams]
</materials>
 
<context>
SLOs: [SLOs, e.g. feed 99.9% available, p99 under
300 ms]. Recovery targets: [RPO and RTO, e.g. RPO
5 minutes, RTO 1 hour for losing a region].
</context>
 
<task>
A failure-mode analysis of this design: how it
behaves when each part fails, and what is missing.
</task>
 
<requirements>
- FMEA form: a row for each component and each arrow,
  for each failure that applies: crash, slow not down,
  zone loss, region loss, network partition, bad deploy
  or config, retry storm, cache stampede, hot partition,
  poison message, disk full, expired certificate,
  provider quota, clock skew, data corruption.
- Rate each row's severity, occurrence and detection
  from 1 to 10 (10 = hardest to detect) and rank by
  their product, the risk priority number.
- Separate the mitigations already in
  the design from the missing ones.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing.
</requirements>
 
<quality_bar>
Before answering, check your analysis against:
- Every box and arrow in the diagram has at least one row.
- Each detection names a metric or
  alert the design actually has.
- Retries appear only where the operation is idempotent.
- The 5 worst rows each get a missing mitigation
  or a stated reason to accept the risk.
</quality_bar>
 
<output_format>
A table: component | failure mode | detection | user
impact | mitigation in design | missing mitigation |
recovery | S | O | D | RPN. Then the 5 worst, ranked.
</output_format>
 
<process>
End with a list of the assumptions you made.
</process>

Mock interview

Stage: review · Use when: you are practicing for a system design round and want your answers scored.

Quick

Interview me on "[question, e.g. design a URL
shortener]" for a [level: mid | senior | staff] backend
role. Answer clarifying questions briefly, give no
hints, push on one hand-wave per stage, then score each
stage against what a strong candidate would have said.

Full

<context>
I'm preparing for a system design interview for a
[level: mid | senior | staff] backend role at [company
type, e.g. a large consumer app]. My weak spots: [weak
spots, e.g. estimates and data modeling].
</context>
 
<task>
A 45-minute mock interview on "[question, e.g.
design a chat app]", then a scored debrief.
</task>
 
<requirements>
- Give me only the question at first. Answer
  clarifying questions briefly, as an
  interviewer would; don't suggest solutions.
- You can't see a clock: I'll type the elapsed
  minutes with each answer. Tell me when I'm
  behind the usual pace (requirements done by 10,
  high-level design by 25, deep dives by 40).
- Interrupt with one deep-dive
  question whenever I hand-wave.
- Score 1–4 on requirements, estimation,
  API and data model, high-level design,
  deep dives, trade-offs and communication.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing.
</requirements>
 
<quality_bar>
Before answering with the debrief, check it against:
- Each weakness quotes or paraphrases
  something I actually said.
- Each comes with what a strong
  candidate would have said instead.
- The scores follow the level I named, not a generic bar.
</quality_bar>
 
<output_format>
During the interview: short turns. At the end: a
score table (area | score | evidence | what strong
looks like), then the 3 things to practice first.
</output_format>
 
<process>
Start when I say "ready". End the debrief with a
list of the assumptions you made about the role.
</process>

Worked example

Weak prompt

Design Twitter.

What's wrong

  • No scope: tweets? search? DMs? ads? The model will cover everything shallowly.
  • No scale and no targets, so the estimates come from nowhere and nothing can be checked.
  • No constraints, no deliverable, no purpose (production or interview practice).
  • Expect a familiar list of boxes (load balancer, microservices, Kafka, Cassandra, Redis) with numbers that aren't derived from anything, and no way to tell whether it's right.

Strong prompt

<context>
I'm learning system design and want a design I can check.
A Twitter-like app; only the home timeline matters here.
In scope: post (text only), follow, home
timeline (newest first, 20 per page). Out
of scope: search, DMs, media, ranking, ads.
Scale: 50M daily active users; each opens the
timeline 10 times a day and posts 0.5 times.
Average 200 followers; a few accounts have 10M+.
</context>
 
<task>
A design for the home timeline at the depth of a
design document's core sections, with each
decision explained in one line so I learn from it.
</task>
 
<requirements>
- SLOs: timeline p99 under 200 ms; 99.9% available;
  a new post may take up to 10 s to reach followers.
- Capacity estimates with formula, inputs and units
  for timeline reads, posts and fan-out writes per
  second, and for timeline cache memory.
- Compare fan-out on write, on read and
  hybrid; handle the 10M-follower accounts.
- Failure modes in FMEA form for: losing a cache
  node, a fan-out backlog, a celebrity post.
- Never invent numbers, names, quotes or sources:
  write [NEEDS SOURCE] where support is missing.
</requirements>
 
<quality_bar>
Before answering, check your draft against:
- Every estimate recomputed a second
  way; daily counts divided by 86,400.
- Every component justified by an estimate or an SLO.
- The fan-out choice cites the follower
  numbers and the 10 s freshness target.
- Each failure mode has detection,
  impact, mitigation and recovery.
</quality_bar>
 
<output_format>
1. Capacity table: quantity | formula
   | inputs | result | units.
2. API for post, follow and timeline (cursor pagination).
3. Data model for posts, follows and precomputed timelines.
4. Fan-out trade-off table and the choice.
5. Mermaid sequence diagrams for posting and for reading.
6. Failure-mode table.
7. What breaks first at 10x.
</output_format>
 
<process>
Ask me up to 3 questions first if anything
missing would change your answer; otherwise go
on. End with a list of the assumptions you made.
</process>

What came back

An illustrative, abridged response:

No questions; assumptions are at the end.
 
1. Capacity (average; peak = 3x)
Quantity       | Formula             | Result
Timeline reads | 50M x 10 / 86,400   | ~5,800/s
Posts          | 50M x 0.5 / 86,400  | ~290/s
Fan-out writes | 25M x 200 / 86,400  | ~5,800/s
Timeline cache | 50M x 200 IDs x 8 B | ~80 GB raw
 
4. Fan-out: hybrid
On write for accounts under 100k followers: the 10 s target
allows asynchronous workers. On read for the few accounts
with 10M+ followers, merged into the timeline when it is
read. Peak fan-out is ~17,000 inserts/s: about 9 workers.
 
6. Failure modes
Fan-out backlog | detection: oldest queued post > 10 s |
impact: stale timelines | mitigation: autoscale workers,
fan out to recently active followers first | recovery:
drain the queue, then backfill the skipped followers
 
Assumptions:
1. The timeline cache keeps 200 post IDs per user.
2. Peak traffic is 3x the average.
3. Users inactive for 30 days are skipped at fan-out and
   rebuilt on their next visit.
4. One worker handles about 2,000 inserts/s.

How an expert judged it

Checked against the prompt's own quality bar:

  • Estimates recomputed: fails. Fan-out writes are 25M posts × 200 followers = 5 billion inserts a day, and 5 × 10⁹ ÷ 86,400 ≈ 58,000/s, not 5,800/s: a lost power of ten, one of the common errors listed under Capacity estimates. It is easy to miss because the wrong figure equals the timeline-read rate two lines above it. The bar asked for a second computation, and the response skipped it.
  • What the error changes: peak fan-out is ≈ 174,000 inserts/s, so by the response's own assumption 4 the worker tier needs about 90 workers, not 9, and the write load on the timeline cache becomes a deep dive of its own.
  • Fan-out choice: passes. Hybrid, citing both the 10 s target and the 10M-follower accounts.
  • The other numbers: pass. 500M reads a day ≈ 5,800/s; 25M posts ≈ 290/s; 50M × 200 × 8 bytes = 80 GB.
  • Assumptions: worth reading. Number 3 (skip inactive users) is a real design decision that cuts the fan-out load; it belongs in the design with an estimate, not in a footnote.

Verdict: fix the arithmetic first; sections 4 and 6 have to be redone from the corrected number.

The follow-up

Fan-out writes are wrong: 25M posts x 200 followers = 5
billion inserts a day, about 58,000/s average and 174,000/s
at peak, not 5,800/s. Redo the capacity table by running
the arithmetic in code, then update only what depends on
it: the worker count, the write load on the timeline cache,
the fan-out deep dive and the fan-out-backlog failure mode.
Move assumption 3 (skip inactive users) into the design,
with an estimate of the load it removes; mark the share of
inactive users [NEEDS SOURCE]. List what you changed.

Judge the output

CriterionWeakStrong
Requirementsfeatures onlyfunctional, non-functional with numbers, and out of scope
Estimatesmissing, or arithmetic wrongcorrect to an order of magnitude, with units, average and peak
Estimates usedcomputed, then ignoredeach major choice cites a number
APIvague verbsconcrete payloads, pagination, idempotency, error cases
Data modeltables before queriesaccess patterns first; keys and indexes serve them
Storage choicenamed by fashionjustified by access patterns, consistency and scale
Bottlenecksnot namedthe first resource to saturate, and the plan for it
Consistencyone level for everythingper operation, with how it is achieved
Failure handling"add redundancy"per-component failure modes, slow dependencies included, with timeouts, retries and idempotency
OperationsabsentSLOs, golden signals, alerts, deploy and rollback
Costabsentmonthly estimate with the main drivers
Trade-offsone optionalternatives rejected for stated reasons; what breaks at 10x
Simplicityevery popular componentthe fewest moving parts that meet the numbers

The same checks are in every <quality_bar> on this sheet, so the model is asked to run them before it answers; the rubric is how you confirm it did.

Follow-up prompts:

Recompute every estimate step by step with units, then
list each design decision and the number that justifies
it. Flag any component no number justifies.
Walk one request through the write path and one through
the read path, naming every network hop, its expected
latency and what happens if that hop times out.
Which dependency in this design, if it became 10x slower
but stayed up, would hurt most? Trace the effect and fix
it.
Cut the monthly cost by half while keeping the SLOs. What
would you change and what risk does each change add?

Pitfalls

PitfallWhat it looks likeCounter it
Arithmetic errorswrong unit, lost power of ten, bits for bytesask for units at every step; recompute; use the code tool
Buzzword stackingKafka, Cassandra, Kubernetes and a service mesh for 50 requests per secondgive the numbers and the team; "simplest design that meets them; justify each component with a number"
"Just add a cache"a cache with no invalidation, TTL or stampede planask what is cached, where, for how long, how it is invalidated, what happens on a miss storm
Eventual consistency for moneybalances or inventory on an eventually consistent pathask for the consistency table per operation
Retries without idempotencyretried payments charge twiceask where retries happen and which operations are idempotent
No timeoutsa slow dependency holds every thread"timeouts and a fallback for every remote call"
CAP misuse"we choose CA"partitions are not optional across a network; ask what happens during one
Wrong availability mathfive services at 99.9% each promised as 99.9% end to endserial dependencies multiply: 0.999^5 ≈ 99.5%
Invented limits and pricesprecise cloud quotas, instance prices or throughput limits from memorycheck the vendor's current docs and pricing pages
Hot keys ignoreduniform load assumedask about the most popular key and the largest tenant
Recited, not reasoneda memorized "standard design" that ignores your requirementsask how each requirement changed the design compared to the textbook answer
Agreeable reviews"this design is robust""find at least 5 problems, ranked, or explain why there are fewer"

References