Requirements and Estimation
Every design starts with what to build and how big it is. Numbers decide whether you need one server or fifty, a cache or a shard.
- 86,400seconds per day, the divisor for QPS
- 3xtypical peak over average QPS
- ~1,160/saverage QPS at 10M DAU, 10 actions each
Show what to say
“I spend the first five minutes on what to build and how big it is: three to five core features, then targets with numbers, like p99 under 200 ms. Then I estimate on the board: average QPS is daily users times actions divided by 86,400, peak about three times that, with reads and writes split. Every number has to end in a design decision.”
Trade-offs
- Precision vs speed: rounding 86,400 to 100,000 gives up exactness but gets the right order of magnitude in under five minutes.
- Average vs p99 targets: p99 is harder to hit, but the slowest 1% are the requests users complain about.
- Sizing for peak vs average: you pay for idle servers off-peak, but running at 60% busy at peak leaves room for spikes.
Bring it up before they ask
Forgetting replicas in the storage estimate: 10M DAU over 5 years is about 17 TB, but 49.8 TB once you keep 3 copies.
Spend the first 10 minutes on what to build and how big it is. Then round the numbers: average = DAU × actions ÷ 86,400, peak ≈ 3×, and each number should justify a design choice.
Why it matters
One server or fifty? A or a ?
Read more · 153 words
The numbers decide. "Add a cache" is a guess until you know reads outnumber writes 50 to 1.
Play Numbers drive the design: five numbers from one estimate become five design choices. Candidate A says "add a cache" at minute 12. Candidate B says "35K reads a second against 700 writes, so cache the feed". Same box, but only B can defend it.
45 minutes goes fast. Say your plan out loud: requirements, a quick estimate, then the design.
Behind at minute 10? Cut the estimate to one number, usually peak , say so, and start drawing. A rough number you used beats a precise one you never reached.
Tap any box to see what it is and what it talks to.
- Client
- Service
- API gateway
- Database
- Cache
Text description
- Instagram-lite: 100M daily users × 10 feed views is about 11.6K reads/s on average and 35K/s at peak, against only about 230 uploads/s.
- Reads outnumber writes 50 to 1, so the feed API is a cheap, cursor-paginated GET /feed; uploads can be slower and asynchronous.
- 10 TB of new photos a day can't live in a database: metadata goes in SQL, image bytes in object storage.
- About 46 Gbps of thumbnail egress makes a CDN mandatory; 35K feed reads/s calls for a cache and precomputed feeds.
- So the deep dive goes to the feed cache, which carries most of the load. If a number changes, update the design out loud.
5 minutes of requirements, 5 of estimation and APIs, 15 of high-level design, 15 of deep dive, 5 to wrap up. Start drawing by minute 10.
Text description
- Requirements: Scope (0–5 min)
- Estimate + APIs: Estimate (5–10 min)
- High-level design: Data model + main paths (10–25 min)
- Deep dive: Bottlenecks + failures (25–40 min)
- Wrap-up: Recap (40–45 min)
Functional and non-functional requirements
"Design Twitter" is vague on purpose.
Read more · 730 words
Functional requirements say what users can do. Non-functional ones say how well the system does it, each with a number. Spend about five minutes on both: ask, cut, write.
Ask three questions. The interviewer's answers become the first lines on your board (under two minutes).
- Who are the users? Readers, writers, admins?
- What are the 3 core actions? Post, follow, read the timeline.
- What can I cut? "I'll skip DMs and ads unless you want them." Cutting shows seniority.
Cut scope out loud. A prompt has 10 to 15 plausible features and you have time for 3 to 5. Play A late request: written scope lets you say what a new feature changes. Video at 1% of tweets is 100 times the text storage, which turns and a from optional into required. Skip the long list when the prompt is already narrow ("Design a "): confirm two things and move on. If the interviewer wants a feature back, you add it.
Write it on the board in three short lists: functional, non-functional, out of scope. More than five core actions and you will not finish in 45 minutes. The board for Twitter-lite:
Functional
- Post a tweet: 280 characters, optional image
- Follow and unfollow users
- Home timeline of followed accounts, newest first
Non-functional
- 200M daily users, reads far outnumber writes
- Timeline p99 under 200 ms
- 99.99% available for reads
- A new tweet shows up in followers' timelines within ~5 s
- Never lose a posted tweet
Out of scope
- Search and trends
- Direct messages
- Notifications
- Ads and ranking
- Editing tweets
"Fast" is not a requirement. " under 200 ms" is. Start from the sentence you heard and walk the tree to find which requirement it becomes. Try "users must see their own post at once" and "recommendations can be slow to update".
| Requirement | Meaning and example target | What it forces |
|---|---|---|
| Latency | How long a request takes, set as a percentile: p99 is the slowest 1%. Propose p99 under 200 ms for a page, tighter for internal calls | Caches, CDN, fewer calls per page |
| Availability | Share of time the system answers, in nines. Each extra nine cuts allowed downtime by 10. Use 99.9% for most products, 99.99% for login, payments and APIs others depend on | More zones, no single point of failure, automatic failover. Do not promise 99.999% unless asked; say what it costs |
| Consistency | Must every reader see the latest write? Strong: one authoritative copy. Eventual: a replica may be a moment behind, and reads scale out | Different stores per feature |
| Durability | A write the system confirmed survives a crash. Acknowledge only after the write is on at least two disks in different zones, and take backups | Replication, backups |
- Consistency, per feature: strong for money, inventory and permissions (a follow button that says "not following" after you tapped it feels broken). Eventual for timelines, likes and counts: a few seconds of lag is invisible, and carry the read load.
- Durability, per feature: likes can be lost occasionally; payments cannot. Say which of your data is which.
- No number given? Propose one and say it out loud. They will correct it, and you have shown you know what matters.
Why p99, not the average. The average hides the slowest 1%, and users meet them far more often than 1%. A page that makes 10 backend calls hits at least one slow call about 1 time in 10. At 100 calls it is nearly 2 in 3.
The chance that all n calls are fast is 0.99 to the power n, so the chance of one slow is 1 − 0.99^n. For n = 10 that is 1 − 0.904 = 9.6%.
Counting nines. 99.9% is about 8.8 hours of downtime a year, 99.99% about 53 minutes, 99.999% about 5 minutes. A chain of components multiplies their availability: two parts at 99.9% in series give 99.8%, about 17.5 hours a year. Two copies in parallel give 99.9999%, if their failures are independent.
Tap any box to see what it is and what it talks to.
- Client
- Service
- API gateway
- External API
Text description
- Twitter could mean posts, follows, timelines, search, trends, DMs, ads and more. List them quickly.
- Keep the three that define the product: post a tweet, follow a user, read the home timeline.
- Park the rest and say so: I'll skip DMs, search and ads unless you want them. Cutting shows judgement.
Would a wrong or lost answer cost money or trust (payments, orders, follows)?
Show data table
| Backend calls per page | At least one slow call (%) |
|---|---|
| 1 | 1 |
| 10 | 9.6 |
| 25 | 22.2 |
| 50 | 39.5 |
| 100 | 63.4 |
Back-of-envelope math
You want the right order of magnitude in five minutes, not the right answer.
Read more · 835 words
Round hard: 86,400 becomes 100,000, and the result is off by about 16%, which does not change any decision. Play to servers, Storage and Bandwidth. Each box is one line on the board.
| Quantity | How | 10M DAU, 10 actions each |
|---|---|---|
| Average QPS | DAU × actions ÷ 86,400 | ~1,160/s |
| Peak QPS | average × 3 | ~3,500/s |
| Storage | writes/s × 86,400 × days × bytes × replicas | ~50 TB over 5 years |
| Servers | peak ÷ (per-server QPS × 0.6) | 6 at 1,000 req/s each |
- QPS (queries per second) is the first number because every other builds on it. Shortcut: 1M requests a day is about 12 a second, so 100M a day is about 1,200 a second. Use a peak factor of 2 to 5 for daily traffic and 10 or more for events such as a sale or a live match. Always size for the peak: 1,160 a second looks calm until the evening spike.
- Storage: do it in one line so the copies cannot be forgotten. 105 writes/s × 86,400 s × 1 KB ≈ 9 GB a day. Over 5 years that is 16.6 TB, and with 3 49.8 TB. Use for photos and video and keep only metadata in the database. Tweets and rows are small; media fills disks.
- Bandwidth: requests per second times bytes per response, times 8 to get bits. Text is almost nothing; photos and video decide the architecture. When media pushes the origin past about 1 Gbps, a is the usual answer, and it is faster for far-away users too. Links are rated in bits per second (Gbps), disks and files in bytes: convert once and write the unit on every line.
- Servers: assume about 1,000 requests a second for a simple API, run at 60% busy, and say you would load-test that number.
- Memory for a follows the 80/20 rule: the hottest 20% of items serve most reads. 1,050 reads/s × 86,400 s × 20% × 1 KB is an upper bound of about 18 GB, which fits in one node.
Every 10× in users changes the architecture:
Do the sum first. At 350 peak QPS one server copes; a second is for , not load. At 3,500, a handful behind a balancer. At 35,000, one database can't serve every read, so add a cache and replicas. Don't at 350. The thresholds are rules of thumb, so walk the tree and say them as such.
Split reads from writes. Same QPS, different design: reads scale with caches and replicas, writes with and queues. Work out the ratio, then pick the row.
| Ratio (reads:writes) | Typical products | Design |
|---|---|---|
| 100:1 or more (read-heavy) | URL redirects, news feeds, product pages | Cache in front, CDN, read replicas, precompute results such as feeds. 35,000 reads/s at a 99% hit ratio leaves 350 for the database. Cost: staleness; a second of replica lag is normal |
| ~10:1 | Typical web apps, e-commerce | Cache hot entities, a replica or two for reporting and failover, one primary. The right default when you have no ratio yet |
| ~1:1 | Chat, collaborative editing, multiplayer state | Writes are the hot path, so caching does not rescue you. Partition by a key that keeps related data together (conversation id), append-only storage. 23K writes/s becomes 64 partitions of about 360 each. Watch out: a hot partition, such as a huge group chat, needs its own handling |
| Write-heavy | Metrics, logs, IoT, click streams | Queue in front for bursts, batched writes, an append-friendly engine such as an LSM tree (Cassandra). Cost: data is visible only after the batch lands, so it fits dashboards, not "show me my own click now". Downsample old data (hourly averages, not every second) |
Tap any box to see what it is and what it talks to.
- Client
- Service
- Load balancer
- Worker
- Object storage
- API gateway
Text description
- 10M users x 10 actions = 100M actions a day. Divide by 86,400, which is about 10 to the 5th: about 1,160 requests per second.
- Traffic is not flat. Peak is about 3 times the average, so about 3,500 per second. Size for this number, not the average.
- One server does about 1,000 req/s, but run it 60% busy for headroom: 600 usable. 3,500 / 600 = 5.8, so 6.
- Run 9 across three zones so losing a whole zone still leaves 6. The extra three are for failure, not load.
Is peak under about 1,000 requests per second?
Worked example: Instagram-lite
100M DAU, 10% upload 2 photos a day, everyone opens the feed 10 times a day, peak is 3× average.
Read more · 357 words
Peak feed reads are 50 times the peak uploads.
Uploads per second
100M × 10% × 2 = 20M uploads a day ≈ 230/s, ~700/s at peak. One handles the metadata.
Media storage
20M × 500 KB = 10 TB a day, ~3.65 PB a year. Photos go to (S3); the database keeps only metadata.
Feed reads
100M × 10 views = 1B feed loads a day ≈ 11.6K/s, ~35K/s at peak. That is 50× the uploads, so and precompute this path.
Egress bandwidth
10 thumbnails × 50 KB = 500 KB per view, so 11.6K/s ≈ 5.8 GB/s ≈ 46 Gbps (bytes × 8). A is non-negotiable: if it answers 95% of thumbnail requests, the origin carries 46 Gbps × 0.05 ≈ 2.3 Gbps.
Say what it means
"Writes are small: one Postgres primary with . Photos go to object storage behind a CDN. The feed is the hot path at 35K reads/s, so I'll precompute feeds into a cache."
Check storage on a second product. Twitter-lite stores small rows, so the media decides everything. 200M DAU × 2 tweets × 1 KB = 400 GB a day, 730 TB over 5 years, about 2.2 PB with 3 replicas. If 1 tweet in 10 has a 500 KB image, that adds 40M × 500 KB = 20 TB a day, 50 times the text. Text goes in a database and images in object storage; the estimate told you that before you drew anything.
Show data table
| req/s | |
|---|---|
| Uploads | ~700 |
| Feed loads | ~35K |
Numbers to remember
Memory is about 1,000× faster than an SSD read.
Read more · 343 words
One cross-continent round trip costs as much as 10 to 100 indexed database reads. The cheatsheet repeats these.
Latencies span six orders of magnitude, so each step down the list is a design decision. A at about 1 ms against a database read at about 5 to 50 ms is why you . A cross-continent round trip is why you put data near users.
| Quantity | Value |
|---|---|
| Seconds per day | 86,400 ≈ 10⁵, so 1M requests/day ≈ 12/s |
| Seconds per month / year | ≈ 2.6M (100M/month ≈ 40/s) / ≈ 31.5M |
| 2¹⁰ / 2²⁰ / 2³⁰ / 2⁴⁰ | ≈ thousand / million / billion / trillion: KB, MB, GB, TB |
| Typical sizes to assume | tweet or row ~1 KB, thumbnail ~50 KB, photo ~500 KB, a minute of 720p video ~20 to 40 MB |
| Typical web API instance | hundreds to a few thousand req/s (assume, then say "I'd measure") |
| One Redis instance | ~100K simple ops/s; a GET over the network ~0.5–1 ms |
| One Postgres primary | thousands to tens of thousands of simple queries/s, depending heavily on the query |
State sizes as assumptions ("I'll assume 500 KB a photo"): the interviewer cares that you chose one and used it. Machine figures are order-of-magnitude and depend on hardware and query, so use them to decide how many boxes, then add "I'd load-test this".
Pick a preset or drag the sliders; every number moves together. Choose Instagram-lite and watch egress bandwidth dominate. Choose Chat and note how few reads there are per write, so writes become the hot path. Open the extra controls and drop the to 1: storage falls by two thirds.
Show data table
| ns | |
|---|---|
| Memory | 100 ns |
| SSD read | ~100 µs |
| Same-DC hop | ~0.5 ms |
| DB read | 1 to 10 ms |
| HDD seek | ~10 ms |
| Across continents | 100 to 150 ms |
Code
estimate.js counts : 10M DAU over 5 years is 17 TB without them and 49.8 TB with 3.
Read more · 26 words
Forgetting them is the most common storage mistake. serversNeeded applies the 60% headroom and cacheGB the 80/20 rule, so you can rerun your own scenario.
const SECONDS_PER_DAY = 86_400;
// Rough numbers, rounded for saying aloud. Inputs are per day unless noted.
export function estimate({ dau, actionsPerUser, readWriteRatio = 10, bytesPerWrite = 1_000, years = 5, replicas = 3, peakFactor = 3 }) {
const qps = (dau * actionsPerUser) / SECONDS_PER_DAY;
const writeQps = qps / (readWriteRatio + 1);
const readQps = qps - writeQps;
const storageBytes = writeQps * SECONDS_PER_DAY * 365 * years * bytesPerWrite * replicas;
return {
avgQps: Math.round(qps),
peakQps: Math.round(qps * peakFactor),
readQps: Math.round(readQps),
writeQps: Math.round(writeQps),
storageTB: +(storageBytes / 1e12).toFixed(1),
ingressMBps: +((writeQps * bytesPerWrite) / 1e6).toFixed(2),
};
}
// Servers at a target utilization (headroom), given what one instance can handle
export const serversNeeded = (peakQps, perServerQps = 1_000, headroom = 0.6) =>
Math.ceil(peakQps / (perServerQps * headroom));
// Upper bound for caching the hottest 20% of a day's reads (80/20 rule)
export const cacheGB = (readQps, bytesPerItem, hotFraction = 0.2) =>
(readQps * SECONDS_PER_DAY * hotFraction * bytesPerItem) / 1e9;
// estimate({ dau: 10e6, actionsPerUser: 10 })
// → { avgQps: 1157, peakQps: 3472, readQps: 1052, writeQps: 105, storageTB: 49.8, ingressMBps: 0.11 }
// serversNeeded(3472) → 6 · cacheGB(1052, 1_000) → ~18.2Requirements and estimation in the interview
Do this at the very start, before any box is drawn, and keep it to about 10 minutes.
Read more · 751 words
Walk through five decisions in order, because the order shows you have done this before.
Ask who and what
Name the users and agree 3 to 5 core actions. Say what you will skip: "no DMs, no ads, unless you want them."
Put numbers on quality
as a , availability as nines, and which data needs strong consistency. If no number is given, propose one.
Estimate on the board
Average and peak , the read:write split, storage with , and bandwidth if media is involved. Round hard.
Say what each number means
End every line with "so we need": a , a , , a . This is the step interviewers score.
Revisit when scope moves
When a requirement changes, redo only the affected line out loud: "video changes the storage estimate by 100×."
Most estimates fail in the same three ways. Play Forgot the peak, Forgot the copies and Bits and bytes.
| Mistake | What goes wrong | Fix |
|---|---|---|
| Sizing for the average | At 20:00 traffic is about 3 times the daily average, so two servers that looked comfortable at 1,160 a second are overrun at 3,500 | Write peak next to average on every traffic line and size for peak at 60% busy. For known events, use 10× or ask for the peak |
| Forgetting replicas | Planning 17 TB when production keeps 3 copies means 49.8 TB are needed, and the disks fill in less than two years | Multiply by the copies on the same line as the years; add headroom for growth |
| Mixing bits and bytes | A factor-of-8 error: 5.8 GB/s is 46 Gbps, not 5.8 Gbps, and a 10 Gbps link carries about a fifth of it | Write the unit on every number, convert once, and say "so we need a CDN" instead of ordering a bigger link |
| Numbers that change nothing | An estimate that ends nowhere wastes time; 10 minutes of arithmetic costs you the design | End every line in "so we need": 35K reads a second, so a cache; 46 Gbps, so a CDN. If a number does not change a box on the board, drop it. Round, state, move on |
| If the interviewer says | You raise |
|---|---|
| "Design Twitter" | Three core actions, two things out of scope, then the numbers |
| "How many users?" | DAU, actions per user, peak factor of 3 |
| "Reads dominate" | Split read and write QPS; cache and replicas |
| "Do we need to shard?" | Compare peak QPS and storage to one machine first |
| "We also need video" | Re-run storage and bandwidth; object storage and a CDN |
Tap any box to see what it is and what it talks to.
- Service
- Client
- Object storage
- API gateway
Text description
- You sized for the average, 1,160 requests per second, and 2 servers looked comfortable.
- At 20:00 everyone opens the app at once: 3,500 per second. Two servers at 1,000 each are overrun and latency climbs.
- Fix: size for peak at 60% busy. 3,500 / 600 rounds up to 6 servers.
Quick checkHow should every estimate line end?
Interview questions
How do you estimate QPS?
DAU × actions ÷ 86,400, then 2–5× for peak. 10M DAU × 10 actions ≈ 1,160/s, about 3,500/s at peak.
Estimate storage for 5 years of tweets.
200M DAU × 2 tweets × ~1 KB = 400 GB a day, 730 TB over 5 years, ≈ 2.2 PB with 3 . Media goes in .
Why split read and write QPS?
They scale with different tools: and replicas vs and queues.
What peak factor do you use?
2–5× for daily traffic, 10× or more for events. Size for peak at 60–70% busy.
How many app servers for 3,500 peak QPS?
At ~1,000 req/s each and 60% busy: 3,500 ÷ 600 → 6. Run 9 across three zones, so losing a zone still leaves 6.
The interviewer gives no numbers. What do you do?
Propose them and say so: DAU, actions per user, peak 3×, 1 KB per record. They will correct what matters.
Check yourself
Question 1 of 5Score 2 out of 3 or better to mark this page complete.