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):
| Step | Question | Ask the model |
|---|---|---|
| 1. Functional requirements | what 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 requirements | how fast, how available, how consistent, how durable, how cheap, where | "Turn 'fast and reliable' into numbers: p99 latency, availability, durability, consistency per operation." |
| 3. Estimates | requests per second (average and peak), storage per year, bandwidth, read:write ratio | "Estimate QPS, storage and bandwidth step by step with units." |
| 4. API | what the clients call, with request and response shapes | "Define the API: endpoints, payloads, pagination, idempotency, errors." |
| 5. Data model | entities, access patterns, keys, indexes; then the store | "List the access patterns first, then choose a store that serves them." |
| 6. High-level design | the boxes and the read and write paths through them | "Draw the read path and the write path separately." |
| 7. Deep dives | the 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 evolution | what 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:
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
| Term | What it means | Say it like |
|---|---|---|
| Functional requirement | something the system does: post, follow, search | "Functional: create short links, redirect, show click counts." |
| Non-functional requirement | a 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 / QPS | requests (or queries) handled per second | "Estimate average and peak QPS for reads and writes separately." |
| Back-of-the-envelope estimate | a quick order-of-magnitude calculation with rounded numbers | "Do a back-of-the-envelope estimate, showing units at every step." |
| Read:write ratio | how many reads per write; drives caching and storage choices | "Assume a 100:1 read:write ratio unless I say otherwise." |
| Access pattern | a specific way data is read or written: by which key, how often, how much | "List the access patterns before proposing tables." |
| SLI / SLO / SLA | service 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 budget | the failure an SLO allows (99.9% leaves 0.1%), spent on releases and incidents | "Explain how the error budget limits release speed." |
| Availability nines | 99.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 scaling | a bigger machine / more machines | "Scale vertically until it stops being cheaper, then horizontally." |
| Stateless service | keeps 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." |
| CDN | content delivery network: servers near users that cache static and cacheable responses | "Serve images and static assets through a CDN." |
| Replication | copies 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 key | splitting data across nodes by a key | "Shard by user ID; check for hot partitions." |
| Hot key / hot partition | one key or shard getting far more traffic than the rest | "How do we handle a celebrity account as a hot key?" |
| Strong vs eventual consistency | every read sees the latest write / reads may be stale for a while | "Strong for balances, eventual for counters." |
| CAP and PACELC | under a network partition choose consistency or availability; else trade latency against consistency | "Using PACELC, what does this store choose with and without a partition?" |
| Quorum | a read or write must reach a majority (or R and W replicas with R + W > N) | "Explain the quorum settings and what they guarantee." |
| Idempotency | doing 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 / log | a 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 delivery | messages may arrive more than once; consumers must be idempotent | "Assume at-least-once delivery and make consumers idempotent." |
| Backpressure / load shedding | slowing producers / rejecting excess work to stay up under overload | "Shed low-priority traffic first when the queue passes N." |
| Rate limiting | capping 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 jitter | give up after a set time; retry after growing, randomized delays | "Timeouts on every call; retries only for idempotent requests, with full jitter." |
| Circuit breaker | stops 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." |
| Failover | switching to a standby when the primary fails | "How long does database failover take, and what is lost?" |
| RPO / RTO | recovery 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 read | precompute 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." |
| Denormalization | storing duplicated data to make reads cheap | "Denormalize the author name into the post for feed reads." |
| Transactional outbox | writing 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." |
| Saga | a multi-service workflow of local transactions with compensating steps on failure | "Model checkout as a saga with compensations." |
| Observability | metrics, logs and traces that explain behavior from outside | "Give the observability plan: golden signals, traces across services, structured logs." |
| Golden signals | latency, 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 method | for every service, watch request rate, errors and duration (Tom Wilkie's method for request-driven services) | "One RED dashboard per service." |
| USE method | for 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 cost | cost 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:
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 secondWorked 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.
| Common error | Example | Catch it by |
|---|---|---|
| Wrong time unit | dividing by 3,600 (seconds per hour) instead of 86,400 (per day) | 1M/day must come out near 12/s |
| Bits vs bytes | 1.7 GB/s reported as 1.7 Gbit/s, 8x too low | units on every line; network links are sold in bits |
| Lost power of ten | 250M ÷ 86,400 written as 29,000 | round first: 2.5 × 10^8 ÷ 10^5 ≈ 2,500 |
| Forgotten peak | servers sized for average traffic | ask for average and peak in separate columns |
| Forgotten copies | storage without replicas, indexes, backups | ask what multiplies the raw size |
| Unused estimate | numbers 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.
| Component | Failure mode | Detection | User impact | Mitigation | Recovery |
|---|---|---|---|---|---|
| Redis cache | node lost | cache error rate, hit-rate drop | slower feeds; database load spikes | replicas; request coalescing; rate limit refills | automatic failover; warm the cache gradually |
| Postgres primary | crash | health check, replication lag alert | writes fail for the failover time | synchronous standby in another zone | automated failover; check for lost writes |
| Thumbnail worker | poison message | retries exceed limit | some photos lack thumbnails | dead-letter queue after N attempts | fix, then replay the dead-letter queue |
| Payment provider | slow, not down | p99 latency of outbound calls | checkouts hang | timeout, circuit breaker, queue the capture | retry 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.
Brief the model
Each input has a slot in the skeleton; the last column says which.
| Input | Why it matters | Example | Slot |
|---|---|---|---|
| Product and core use cases | scope decides everything | "Photo sharing: upload, follow, home feed, likes. No messaging, no stories." | <context> |
| Users and behavior | the basis of every estimate | "5M daily active users; each views ~50 photos and uploads ~0.2 per day." | <context> |
| Peak pattern | design for peak, not average | "Evening peak ≈ 3x average; launch days 10x." | <context> |
| Data sizes and retention | storage and bandwidth | "Photos ~2 MB original, ~200 KB feed size; keep forever." | <context> |
| Latency targets | which paths need caching or precomputation | "Feed p99 under 300 ms; upload can take seconds." | <requirements> |
| Availability and durability | redundancy level and cost | "Feed 99.9%; uploaded photos must never be lost." | <requirements> |
| Consistency per operation | where strong guarantees are needed | "Likes may lag; a deleted photo must disappear everywhere within a minute." | <requirements> |
| Geography | regions, latency, data residency | "Users in the EU and US; EU data stays in the EU." | <requirements> |
| Existing stack and constraints | stops it designing for a stack you don't run | "AWS, Postgres, Redis, TypeScript; no Kubernetes." | <context> (the stack), <requirements> (the must-nots) |
| Team and operations | what you can actually run at 3 a.m. | "4 engineers, shared on-call." | <context> |
| Budget | rules out over-built designs | "Infrastructure under $5,000/month at launch." | <requirements> |
| Purpose of the exercise | production design vs interview practice need different depth | "Production design doc for a review next week." | <task> |
| Existing design, diagrams, incident notes | a redesign starts from what exists | paste them | <materials> |
What to ask for
| Stage | Deliverable | Ask for it like |
|---|---|---|
| Requirements | requirements 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." | |
| Estimate | capacity estimate | "A table: quantity, formula, inputs, result, units, for QPS, storage, bandwidth, cache size and server count." |
| Interface | API 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." | |
| Data | access 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." | |
| Architecture | high-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 dives | caching 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." | |
| Reliability | failure-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." | |
| Operate | observability 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." | |
| Decide | design 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.
| Task | Completion 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
| Criterion | Weak | Strong |
|---|---|---|
| Requirements | features only | functional, non-functional with numbers, and out of scope |
| Estimates | missing, or arithmetic wrong | correct to an order of magnitude, with units, average and peak |
| Estimates used | computed, then ignored | each major choice cites a number |
| API | vague verbs | concrete payloads, pagination, idempotency, error cases |
| Data model | tables before queries | access patterns first; keys and indexes serve them |
| Storage choice | named by fashion | justified by access patterns, consistency and scale |
| Bottlenecks | not named | the first resource to saturate, and the plan for it |
| Consistency | one level for everything | per operation, with how it is achieved |
| Failure handling | "add redundancy" | per-component failure modes, slow dependencies included, with timeouts, retries and idempotency |
| Operations | absent | SLOs, golden signals, alerts, deploy and rollback |
| Cost | absent | monthly estimate with the main drivers |
| Trade-offs | one option | alternatives rejected for stated reasons; what breaks at 10x |
| Simplicity | every popular component | the 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
| Pitfall | What it looks like | Counter it |
|---|---|---|
| Arithmetic errors | wrong unit, lost power of ten, bits for bytes | ask for units at every step; recompute; use the code tool |
| Buzzword stacking | Kafka, Cassandra, Kubernetes and a service mesh for 50 requests per second | give 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 plan | ask what is cached, where, for how long, how it is invalidated, what happens on a miss storm |
| Eventual consistency for money | balances or inventory on an eventually consistent path | ask for the consistency table per operation |
| Retries without idempotency | retried payments charge twice | ask where retries happen and which operations are idempotent |
| No timeouts | a 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 math | five services at 99.9% each promised as 99.9% end to end | serial dependencies multiply: 0.999^5 ≈ 99.5% |
| Invented limits and prices | precise cloud quotas, instance prices or throughput limits from memory | check the vendor's current docs and pricing pages |
| Hot keys ignored | uniform load assumed | ask about the most popular key and the largest tenant |
| Recited, not reasoned | a memorized "standard design" that ignores your requirements | ask 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
- Designing Data-Intensive Applications (opens in a new tab): replication, partitioning, transactions, consistency and streams in depth
- The System Design Primer (opens in a new tab): a broad index of system design topics with diagrams
- Google SRE book (opens in a new tab): especially Service Level Objectives (opens in a new tab) and Addressing Cascading Failures (opens in a new tab)
- Google SRE workbook: alerting on SLOs (opens in a new tab): error budgets and burn-rate alerts
- Amazon Builders' Library (opens in a new tab): timeouts, retries with backoff and jitter, load shedding, caching
- AWS Well-Architected Framework (opens in a new tab) and its reliability pillar (opens in a new tab): review questions by pillar
- Azure Well-Architected: failure mode analysis (opens in a new tab): how to identify and mitigate failure modes
- Google Cloud Architecture Framework (opens in a new tab): reliability, cost and operational guidance
- Latency numbers every programmer should know (opens in a new tab): Jeff Dean's numbers, by year
- Jepsen: consistency models (opens in a new tab): precise definitions of consistency levels
- Release It! (Michael Nygard) (opens in a new tab): stability patterns such as timeouts, circuit breakers and bulkheads
- Brendan Gregg: the USE method (opens in a new tab): utilization, saturation and errors for every resource
- Grafana Labs: the RED method (opens in a new tab): Tom Wilkie's rate, errors and duration for every service
- OpenTelemetry: observability primer (opens in a new tab): metrics, logs and traces
- Principles of Chaos Engineering (opens in a new tab): testing failure on purpose
- FinOps Foundation: what is FinOps (opens in a new tab): managing cloud cost as an engineering concern