Two candidates get "design Twitter." The first draws a load balancer, three services and a database within ninety seconds and spends forty minutes adding boxes. The second spends eight minutes asking questions and writing numbers, then designs for twenty and evaluates for ten. The second candidate passes, usually with a simpler architecture — because every choice they made pointed at a requirement they had written down.
Why the opening decides the interview
A system design interview is not a test of whether you can name components. It tests whether you can make decisions under uncertainty and justify them. That is impossible without requirements, so an interview that starts with boxes has nothing left to evaluate — every subsequent question ("why sharding?", "why a queue?") gets answered with "because that's how it's usually done," which is the worst answer available.
The opening also does something tactical: it makes the interviewer a collaborator. They know the rubric. When you ask "should I include the ranking algorithm or focus on write fan-out?", they will steer you toward what they intend to score. Candidates who never ask are guessing.
The time budget
| Phase | Minutes (45-min interview) | Output |
|---|---|---|
| Scope and clarify | 4–6 | 2–3 features in scope, explicit non-goals |
| Scale numbers | 3–4 | DAU, RPS, read/write ratio, storage per year |
| Non-functional targets | 1–2 | Latency, availability, consistency, durability |
| API sketch | 2–3 | 3–5 endpoints with shapes |
| Data model | 3–4 | Entities and the access patterns they serve |
| High-level design | 10–12 | The diagram, driven by the numbers above |
| Deep dive | 8–10 | One or two components in real detail |
| Bottlenecks and trade-offs | 5–6 | What breaks first, what you would do next |
Say the plan out loud at the start: "I'll spend about five minutes on requirements and numbers, then sketch the API and data model, then the architecture, and leave time for bottlenecks — stop me if you'd rather go deeper somewhere." That one sentence signals structure before you have designed anything.
Step 1: Scope the problem
Every prompt is deliberately huge. "Design Instagram" is a decade of work for thousands of engineers. Your job is to cut it to two or three features you can design properly, and to say explicitly what you are leaving out.
- Who are the users? Consumers, internal services, third-party developers?
- What are the core actions? Name the two or three that define the product.
- Read-heavy or write-heavy? This shapes everything downstream.
- Global or single region? Multi-region changes consistency and latency assumptions completely.
- Mobile clients? Then offline behaviour, retries and payload size matter.
- What is explicitly out of scope? Say it, and get agreement.
"I'll assume the core is: upload a photo, view a feed of people you follow, and like posts. I'll treat stories, DMs, search, ads and the ranking model as out of scope unless you want them. It's extremely read-heavy — people scroll far more than they post — so I'll optimise the read path and accept more work on writes. Mobile-first, global, so I'll care about payload size, retries and CDN delivery. Does that scope work, or would you rather I focus somewhere else?"
Step 2: Establish the numbers
This is the step that separates candidates. You cannot justify a cache, a shard or a queue without a number attached. Do the arithmetic out loud, round aggressively, and state your assumptions — nobody expects accuracy, they expect a defensible order of magnitude.
1. Traffic 500M users × 20% DAU = 100M DAU Reads: 100M × 50 posts viewed = 5B reads/day ≈ 58,000 reads/sec Writes: 100M × 0.1 posts = 10M writes/day ≈ 116 writes/sec Peak factor 3x → 175k reads/sec, 350 writes/sec Read:write ratio ≈ 500:1 ← the single most important number 2. Storage 10M photos/day × 2 MB = 20 TB/day ≈ 7 PB/year Metadata: 10M × 1 KB = 10 GB/day (trivial by comparison) 3. Bandwidth 175k reads/sec × 200 KB (thumbnails) ≈ 35 GB/s egress → this is a CDN problem, full stop 4. Memory for caching Hot 20% of daily reads × 1 KB metadata ≈ tens of GB → fits in Redis 5. Latency budget Feed render p99 < 200 ms Upload ack < 500 ms (process the rest asynchronously)
Now look what those numbers gave you for free: a 500:1 read ratio justifies precomputing feeds and caching hard; 35 GB/s of image egress means a CDN is not optional; 350 writes/sec means a single database handles the write path comfortably, so proposing sharding for writes would be wrong. You have not designed anything yet and three major decisions are already settled.
1 day ≈ 86,400 s (use 100k for mental maths) 1M/day ≈ 12/sec 1B/day ≈ 12,000/sec Peak is typically 2–5x average Memory read ~100 ns SSD random read ~100 µs (1,000x slower than memory) Disk seek (HDD) ~10 ms Same-region RTT ~1 ms Cross-continent RTT ~150 ms (physics; you cannot optimise this away) One well-tuned SQL primary: ~5k–20k simple queries/sec One Redis instance: ~100k ops/sec One app instance: ~1k–5k rps depending on work per request
Step 3: State non-functional targets
Thirty seconds, four lines, and it earns disproportionate credit because it is where you name trade-offs before anyone asks.
- Latency: p99 targets for the critical paths, not averages.
- Availability: 99.9% versus 99.99% is the difference between one architecture and a much more expensive one.
- Consistency: per operation, not per system. Say which fields are allowed to be stale and which are not.
- Durability: what may be lost on failure? Analytics events, sometimes. Payments, never.
"Different data has different requirements:
- a user's own post must be visible to them immediately (read-your-writes)
- other people's posts may appear seconds late (eventual)
- like counts may be seconds stale and approximate
- follower relationships must be strongly consistent — they control
visibility, so staleness is a privacy bug, not a UX annoyance
So I'll use eventual consistency for the feed and counts, and strong
consistency for the follow graph."That paragraph is the difference between "I'd use eventual consistency" and demonstrating you know consistency is a per-operation choice. The like-count version of that trade-off is worked through in How Instagram handles 1 billion likes.
Step 4: Sketch the API
Three to five endpoints, in about two minutes. The API forces you to be concrete about what the system does, and pagination alone reveals whether you have thought about scale.
POST /posts
body: { caption, mediaUploadId }
→ 201 { postId } (media uploaded separately to object storage)
GET /feed?cursor=<opaque>&limit=20
→ 200 { items: [...], nextCursor }
cursor-based, never offset — offset pagination breaks on inserts
and gets slower the deeper you go
POST /posts/:id/likes
header: Idempotency-Key: <uuid>
→ 200 { liked: true, count } count is approximate and cached
DELETE /posts/:id/likes → 204
GET /users/:id/posts?cursor=...&limit=20Two details worth calling out as you write it: cursor pagination rather than offset, and an idempotency key on the mutating endpoint. Both are small, both signal production experience, and the second connects to the reasoning in duplicate payments.
Step 5: Data model and access patterns
Do not list tables. List the queries the product needs, then show a model that serves them. That ordering is the whole point, and it is what makes a "why NoSQL?" question answerable.
Queries the product requires:
1. feed for user U, newest first, paginated ← highest volume by 500x
2. all posts by user U, newest first
3. one post by id
4. did U like post P
5. like count for post P
Model:
posts(post_id PK, user_id, caption, media_url, created_at)
index (user_id, created_at DESC) → query 2
follows(follower_id, followee_id) PK both
index (followee_id) → fan-out on write
likes(post_id, user_id) PK both → query 4 (idempotent insert)
index (user_id, post_id) → reverse lookup
like_counts(post_id, count) maintained async → query 5
Query 1 is not served by any of these — it needs a precomputed
feed per user, which is the central design decision and where
I'd spend the deep dive.That last line is a gift to your interviewer: you have identified the hard part yourself and proposed where to go deep. Now the "choose your own follow-up" is one you are prepared for.
Only then: draw the system
With scope, numbers, targets, API and access patterns on the board, the architecture almost writes itself, and every component has a reason attached:
Clients ──▶ CDN (35 GB/s of images — mandatory)
──▶ API gateway (auth, rate limiting, per-key quotas)
──▶ Post service (350 writes/sec — one primary is plenty)
──▶ Feed service (175k reads/sec — served from cache)
Post write ──▶ posts table ──▶ outbox ──▶ stream
├──▶ feed fan-out workers
├──▶ counter aggregation
└──▶ notifications
Feed read ──▶ Redis precomputed feed ──▶ hydrate post metadata
(cache hit rate ~95%)Then say what you deliberately did not do and why: "no sharding on the write path, because 350 writes/sec doesn't need it — I'd rather spend complexity on feed fan-out, which is where the 500:1 ratio actually hurts." Restraint justified by a number is one of the strongest signals you can give.
For how the read-path numbers translate into failure modes at every hop, see What happens when 10M users hit your API.
Phrases that buy you credibility
- "Let me get the numbers first, because they'll decide most of this."
- "I'm assuming X — tell me if that's wrong and I'll adjust."
- "I'll start simple and add complexity only where the numbers force it."
- "The trade-off I'm accepting here is ..."
- "This is the part that breaks first, and here's how I'd know."
- "I don't know the exact figure, but it's around N — order of magnitude is what matters here."
- "Would you rather I go deeper on this or move on?"
Mistakes that end interviews early
| Mistake | What the interviewer concludes | Instead |
|---|---|---|
| Drawing a load balancer in the first minute | Pattern-matching, not reasoning | Ask questions and write numbers first |
| No numbers anywhere | Cannot justify any decision | Compute five numbers out loud |
| Designing every feature shallowly | Cannot prioritise | Pick 2–3 features and go deep |
| Proposing microservices, Kafka and sharding immediately | Cargo-culting scale | Start simple; add only what a number demands |
| Silence while thinking | Nothing to evaluate | Narrate: 'I'm weighing X against Y because...' |
| Never naming a trade-off | Believes there is one right answer | State what you gave up in every choice |
| Ignoring interviewer hints | Not collaborative | When they ask twice about something, go there |
| Running out of time mid-diagram | No time management | Announce a time plan at the start |
The template
1. SCOPE (5 min) Core features (2–3) · explicit non-goals · read or write heavy · global or regional · confirm with the interviewer 2. NUMBERS (4 min) DAU · requests/sec average and peak · read:write ratio · storage per day and per year · bandwidth · cache size · latency budget 3. TARGETS (2 min) p99 latency · availability · consistency PER OPERATION · durability 4. API (3 min) 3–5 endpoints · cursor pagination · idempotency keys on mutations 5. DATA (4 min) Access patterns first · then entities and indexes · name the query no model serves — that is your deep dive 6. DESIGN (12 min) Draw it. Every box justified by a number from step 2. Say what you deliberately did not build. 7. DEEP DIVE (10 min) One component in real detail: the hardest access pattern. 8. BOTTLENECKS (5 min) What breaks first · how you would detect it · what you would do next · the trade-offs you accepted
Summary
- The first ten minutes decide the interview; spend them on requirements, not boxes.
- Cut the prompt to two or three features and state your non-goals aloud.
- Compute DAU, RPS, read:write ratio, storage and bandwidth — every later decision references them.
- State consistency per operation, not per system.
- Sketch the API and the access patterns before the data model.
- Justify every component with a number, and name what you deliberately left out.
- Narrate your reasoning and follow the interviewer's hints.