System design interviews usually open with a deliberately broad question like "Design Instagram." That single line could mean photo uploads, stories, feeds, messaging, recommendations, notifications, or media storage.
A weak answer starts solving before understanding the problem. The candidate either freezes because the question is open-ended, or immediately draws the system they memorized for "Instagram."
The first job in an interview is to narrow the problem enough that every design decision has a reason.
In this chapter, I'll give you a practical flow for handling most system design interviews. Treat it as a default path, not a script: adapt it based on the interviewer, the question, and the time left.
System design interviews work differently from coding interviews. There's no single correct answer, there are no test cases to validate your solution, and there's no compiler to tell you whether you're right or wrong.
The interviewer gives you an ambiguous problem and 45-60 minutes to show how you reason through a design problem. A simple framework keeps you from drifting while leaving room to follow the interviewer's signals.
When you have a mental checklist, you spend less energy wondering what to do next. That frees you to think about the actual system.
Candidates often over-focus on one area: a detailed architecture diagram with no scale, detailed APIs with no data model, or a happy path with no failure story. A framework helps you cover the major areas without over-investing in any one of them.
System design is collaborative. A structured answer makes it easy for the interviewer to redirect you: "skip APIs," "go deeper on storage," or "assume 10x traffic." When that happens, you are designing with them rather than reciting a memorized answer.
45-60 minutes disappears quickly. If you spend 25 minutes clarifying requirements, you will not have time for deep dives. A framework gives you rough checkpoints so you know when to move on.
Interview anxiety is real, even for experienced engineers. When your mind blanks, a familiar structure keeps you moving: clarify scope, estimate scale if useful, draw the baseline, then deepen the most important part.
Here is a default flow I recommend for system design interviews. The order is a starting point, not a fixed sequence. Some interviews skip estimation. Some go straight from requirements to high-level design. Some spend most of the time on one subsystem. When the interviewer nudges you in a direction, go with it.
| Phase | Duration | Purpose |
|---|---|---|
| 1. Requirements | 5-7 min | Define what to build |
| 2. Estimation | 3-5 min | Understand the scale |
| 3. API Design | 3-5 min | Define key interfaces, if useful |
| 4. High-Level Design | 8-10 min | Draw the baseline architecture |
| 5. Database Design | 5-7 min | Model the data |
| 6. Deep Dives | 12-18 min | Detail critical components |
| 7. Wrap-Up | 3-5 min | Discuss bottlenecks and improvements |
The phases usually build on each other. Requirements inform your estimates. Estimates influence the architecture. The architecture exposes the data model and bottlenecks. The bottlenecks become deep dives.
What matters is knowing when to spend less time on a phase. If the interviewer says, "Don't worry about exact numbers," keep estimation short and move on.
This is the foundation of the answer. If you get the scope wrong, the rest of the design can be technically impressive and still solve the wrong problem.
Real systems exist within constraints. A messaging app for 1,000 users requires a completely different architecture than one designed for 1 billion users. A payment system that can tolerate 5 seconds of latency has different requirements than one that needs sub-100ms response times.
The question is usually vague on purpose. "Design Instagram" could mean a hundred different things, and part of what the interview measures is whether you can work through that ambiguity and extract the information you need before committing to a solution.
Treat this phase as a conversation, not an interrogation. Propose a reasonable scope, let the interviewer adjust it, then move.
These define what the system should do. Start by proposing a scope and let the interviewer refine it:
Example for "Design Instagram":
"Let me make sure we're aligned on scope. I'm thinking we should focus on the core Instagram experience: sharing posts, following users, and viewing a home feed.
Should we also include features like direct messages, stories, search, or reels? Or should we keep those out of scope for this discussion?"
This is stronger than asking "What features do you want?" It shows product awareness while still giving the interviewer room to adjust the scope.
These define the quality attributes your system must meet. The most important ones to clarify:
Example dialogue:
You: "What scale should we design for? I want to make sure we're thinking about the right order of magnitude."
Interviewer: "Let's say 500 million daily active users."
You: "Got it, so we're at a scale where caching and partitioning will probably matter. For the home feed, what latency is acceptable? Sub-second? Sub-200ms?"
Interviewer: "The feed should load within 200ms."
You: "That pushes us toward pre-computed or cached feeds. One more question: is eventual consistency acceptable for fan-out? Meaning if I share a post, it's okay if it takes a few seconds to appear in my followers' feeds?"
Interviewer: "Yes, that's fine."
Write down the requirements as you discuss them. They give you a reference point to return to when you justify design decisions later. Keep each note short and concise so it’s easy to write down quickly.
Functional Requirements:
Non-Functional Requirements:
Jumping into design after one or two questions often leads to solving the wrong version of the problem.
You don't need perfect information to start designing. If you're still clarifying after 7 minutes in a 45-minute interview, make reasonable assumptions and move on.
Sometimes the interviewer won't give you a direct answer. That's intentional. When this happens, make a reasonable assumption and state it explicitly: "I'll assume we need to support 100 million messages per day. If that's off, we can adjust."
Most system design interviews don't require detailed capacity estimates. Check whether the interviewer wants estimates, and keep the math rough and simple.
Avoid going into too much detail. You do not want to spend valuable interview time doing calculator-style arithmetic.
Estimation turns vague scale into design pressure. A system handling 100 requests per second may not need the same architecture as one handling 100,000. Keep the math rough; the goal is to identify bottlenecks, not produce a capacity plan.
Calculate queries per second for both reads and writes. The distinction matters because reads and writes scale differently.
That gives a 5:1 read-to-write ratio, and 10 feed views per user per day is a conservative assumption. Active users refresh far more often, so the real ratio skews higher. Either way, the takeaway holds: this is a read-heavy system, and caching will be critical.
Estimate how much data you'll accumulate over time. This determines whether you can fit everything on a single machine or need distributed storage.
730 TB covers only the post metadata, and it's already beyond what a single database node should hold, so we'll need partitioned or distributed storage. The photos and videos themselves are much larger, so they live in object storage fronted by a CDN rather than in the primary database.
Many interviews skip bandwidth and stop at QPS and storage. If it comes up, a rough calculation shows whether the network could become a bottleneck. Each feed read returns a page of posts, so assume 20 posts per page here.
The estimation phase is not arithmetic for its own sake. Each number you calculate should influence a design decision:
Use powers of 10. The goal is order of magnitude, not precision. 86,400 seconds per day? Just call it 100,000. You're trying to determine if you need one server or one thousand, not the exact count.
Every calculation depends on assumptions. Make them explicit: "I'm assuming each user views their feed 10 times per day. That might be low for active users, but it gives us a conservative baseline."
Walk through the calculation verbally so the interviewer can follow how you arrived at the number, not just the result.
For many interviews, it helps to sketch the key APIs before drawing internals. APIs clarify the system boundary and force you to name the main operations. How much this phase matters depends on the problem. If the interviewer wants to get to the architecture, define a couple of core endpoints and move on.
You can't design an endpoint without understanding exactly what operation it performs and what data it needs. If you're fuzzy on the API, you're fuzzy on the requirements.
APIs reveal what data flows through your system. The moment you define a "GET /feed" endpoint that returns posts, you've committed to a system that can query and assemble feed data efficiently.
Defining the API makes clear that you understand what clients ask the system to do, not just the infrastructure behind it.
For each core feature, specify:
Keep the detail light. You're not writing API documentation. Focus on the core operations that map to your functional requirements.
For any endpoint returning lists, mention that you'd use cursor-based pagination rather than offset-based. Cursors handle real-time data better since they're stable even when new items are inserted.
For write operations like payments or orders, mention idempotency keys. This allows clients to safely retry requests without creating duplicates.
Briefly acknowledge that public-facing APIs need rate limiting to prevent abuse. You don't need to design the rate limiter here, just show awareness.
The goal is to make the client-facing behavior concrete. Do not spend interview time polishing exact JSON fields unless the API itself is the focus.
Now you draw the architecture. This is where you show how different components work together to satisfy the requirements you defined earlier.
A common mistake is trying to draw the final architecture immediately. You'll end up with a confusing diagram that's hard to explain and easy to get lost in.
Instead, start with the simplest design that could possibly work, then add components incrementally as you identify problems.
This approach has two advantages: it's easier for the interviewer to follow your reasoning, and it demonstrates that you understand why each component is necessary.
This handles the happy path, but one server is a single point of failure. If it crashes, the system becomes unavailable even though the database still has the data.
Now we have redundancy. But we calculated 175,000 read QPS at peak. Hitting the database for every read won't scale.
Each addition should solve a specific problem. Avoid adding components just because they appear in many diagrams.
For each core use case, explain how data flows through the system. This demonstrates that your architecture works and isn't only a collection of boxes.
Walking through the flow reveals the message queue and clarifies the consistency trade-off: the author sees success before every follower feed is updated.
For an Instagram-like system, the full design might look like this:
| Component | When to Include |
|---|---|
| Load Balancer | Multiple app instances, availability, horizontal scaling |
| Cache | High read traffic, expensive computations |
| Message Queue | Async processing, decoupling services, handling spikes |
| CDN | Static content, global user base |
| Database Replicas | Read-heavy workloads |
| Sharding | Large data volumes, write scalability |
| Rate Limiter | Public APIs, protecting against abuse |
Don't just draw boxes. Explain why each component exists: "We estimated high feed read traffic, so I want a cache or pre-computed feed layer instead of hitting storage for every request."
Use consistent shapes, clear labels, and arrows showing data flow. The diagram should be easy to scan and easy to change.
Name your services, databases, and queues. "Cache" is fine; "Feed Cache" is better.
At this point, you'll have a working architecture but with some hand-waving. That's expected. "This design works, but we'll need to discuss how fan-out handles high-follower accounts in the deep dive."
With your architecture sketched out, it's time to define how you'll store and organize your data. The database design often becomes the foundation for deep dive discussions, so getting this right matters.
Many candidates skip this step or treat it as an afterthought. That is risky because the data model usually determines whether the design can serve the required access patterns.
Your data model influences almost every other aspect of the system. Query patterns depend on how data is organized. Sharding strategies depend on your access patterns. Caching decisions depend on what data is read together. By explicitly designing your data layer, you're setting up the rest of your discussion to be coherent and grounded.
Start by naming what each store is responsible for. Is it the source of truth, a cache, a search index, or a derived view? Then choose the database category that fits the access pattern.
Choose a relational database (SQL) when:
Choose a NoSQL database when:
Example for Instagram:
For our Instagram design, we have three main entities:
| Entity | Database Choice | Rationale |
|---|---|---|
| Users/Follows | PostgreSQL | Structured data, constraints, and relationship queries |
| Posts | Cassandra | High write volume, time-ordered reads by user |
| Feeds | Redis | Pre-computed lists, fast reads, can rebuild from posts |
For each data store, define the key tables or collections and their fields. Focus on the fields that matter for your queries.
A single follows table with a composite primary key (follower_id, followee_id) records each relationship once. To serve both directions of the query, "who does X follow?" and "who follows X?", add a secondary index on followee_id. The composite key already makes "who does X follow?" efficient since rows for one follower are stored together.
The partition key (user_id) means posts from one user are stored together, making "get this user's recent posts" efficient. In a real Cassandra table you would usually include a time bucket or similar strategy to avoid unbounded partitions for extremely active accounts.
The feed is a simple list of IDs. When a user loads their feed, we fetch the IDs, then batch-fetch the post objects.
For each query your system needs to support, verify that your schema can handle it efficiently.
| Query | How It's Served |
|---|---|
| Get home feed | Read from Redis list, batch-fetch posts |
| Share a post | Write to Cassandra, publish to queue |
| Get user's posts | Query Cassandra by user_id partition |
| Follow a user | Insert one row into follows, update counts asynchronously |
| Get followers | Query follows by the followee_id index |
If an access pattern requires a full table scan or joining across shards, that's a sign your schema needs adjustment.
For large-scale systems, explain how you'd partition your data.
Posts: Partition by user_id plus a time bucket if needed. This keeps recent posts by a user efficient to fetch while avoiding unbounded partitions. Very active or high-follower users may need special handling, such as splitting partitions, caching hot reads, or treating fan-out differently.
Users: Shard by user_id using consistent hashing. User data is relatively small and accessed by ID, making this straightforward.
Follows: Sharding this is trickier. A secondary index serves both query directions on a single node, but once the table is partitioned, the index direction no longer lives with the data it points to. At that point, maintaining a second copy partitioned by followee_id keeps "who follows X?" fast, at the cost of writing each follow to both layouts.
In NoSQL especially, you often design your schema around how you'll query it, not around normalized entity relationships. If you need to query data a different way, you might need a second table with the same data organized differently.
Storing follower_count on the user record means we don't have to count rows for every profile view. The trade-off is maintaining consistency when follows change. Be explicit about these choices.
You don't need every field. Focus on the ones that affect your design decisions: primary keys, partition keys, foreign keys, and any denormalized fields.
This is often where most of the signal comes from. The high-level diagram shows breadth, while the deep dive shows whether you understand the hard part of the system you just drew.
The interviewer may pick a topic, or they may ask where you want to go deeper. If you get a choice, pick the area most central to the requirements: feed generation for Instagram, booking correctness for Ticketmaster, idempotency and ledgering for payments, partitioning for a key-value store.
Common deep dive topics include:
The topics that come up depend on your design. If you draw a cache, be ready for invalidation. If you mention sharding, be ready for partition keys and hot spots. If you add a queue, be ready for retries, ordering, duplicate processing, and backpressure.
For any topic, follow this structure:
Start by stating what challenge you're solving. This confirms you understand why this is a deep dive topic.
"The challenge with fan-out is the high-follower account problem. When someone with 10 million followers shares a post, we can't write to 10 million feed caches synchronously."
Show that you know there are different ways to solve the problem. Two approaches with clear trade-offs is better than five shallow options.
"There are a few approaches we could take. We could use push-based fan-out where we write to followers' feeds immediately, pull-based fan-out where we compute feeds on read, or a hybrid approach."
Walk through the mechanics of each approach. Be concrete. Use your diagram to trace the flow.
Every approach has pros and cons. A strong answer shows what you optimize for and what you are willing to give up.
Don't leave the decision hanging. State which approach you'd choose and why. Ground it in your requirements: "Given our latency requirement of 200ms for feed loads, I'd choose the hybrid approach because..."
The Problem: When a user shares a post, how do we update the feeds of their followers?
When a user shares a post, immediately write it to all followers' feed caches.
When a user requests their feed, fetch posts from all followed users in real-time.
Use push for regular users and pull for high-follower accounts.
Recommendation: "I would use the hybrid approach. For normal accounts, fan out on write so feed reads stay fast. For high-follower accounts, store the post and merge it into feeds at read time. The exact threshold should be based on follower count, posting frequency, and worker capacity, not a hard-coded magic number."
For complex decisions, a small comparison table can help. Keep it short; the table should support the discussion, not replace it.
| Approach | Write Latency | Read Latency | Storage | Best For |
|---|---|---|---|---|
| Push | High | Low | High | Active users |
| Pull | Low | High | Low | Inactive users |
| Hybrid | Medium | Low | Medium | Mixed workloads |
Here are a few other topics that frequently come up, along with the key points to address:
Data Sharding:
Caching Strategy:
Consistency Models:
For each of these, the pattern is the same: state the problem, compare realistic approaches, explain the trade-offs, and make a recommendation tied back to the requirements.
The final phase should be brief. You are not introducing a new design. You are showing that you understand what you built, where it is weak, and what you would improve next.
Spend 30 seconds recapping the key components and how they work together. This reinforces the coherence of your design.
"To summarize: we have separate Post, Feed, and User services. We use a hybrid fan-out approach, pushing to regular users' feed caches and pulling high-follower accounts at read time. Feed data is stored in Redis for sub-200ms reads, and we use Kafka to decouple the write path from fan-out processing."
Show that you understand the limitations of your design. Pick the bottlenecks that match your architecture.
"The main bottlenecks I see are fan-out lag during viral events and cache pressure on feed reads. I would monitor queue depth, fan-out latency, cache hit rate, and read latency. If fan-out falls behind, we can degrade gracefully by merging more content at read time."
What would you build next if you had more time? Mention only improvements connected to the original scope.
"If we had more time, I would add rate limiting for write APIs, improve multi-region failover, and define a separate search/indexing path. I would keep recommendations out of scope unless the interviewer wants to explore ranking."
Be ready for questions that push on your design:
These questions test whether you can adapt your design. You don't need a perfect answer. Start from the bottleneck or failure mode, then adjust the architecture.
Time goes quickly in a system design interview. Use these as rough checkpoints, not a rigid agenda:
| Phase | Duration | Cumulative |
|---|---|---|
| Requirements | 5-6 min | 6 min |
| Estimation | 3-4 min | 10 min |
| API Design | 3-4 min | 14 min |
| High-Level Design | 7-8 min | 22 min |
| Database Design | 4-5 min | 27 min |
| Deep Dives | 15-16 min | 43 min |
| Wrap-Up | 2 min | 45 min |
| Phase | Duration | Cumulative |
|---|---|---|
| Requirements | 5-7 min | 7 min |
| Estimation | 3-5 min | 12 min |
| API Design | 3-5 min | 17 min |
| High-Level Design | 8-10 min | 27 min |
| Database Design | 5-7 min | 34 min |
| Deep Dives | 18-20 min | 54 min |
| Wrap-Up | 4-6 min | 60 min |
Glance at the time periodically. You don't want to realize you've spent 25 minutes on requirements.
Know where you should roughly be: "By 15 minutes, I should probably be drawing the high-level design."
If a topic is taking too long, move on clearly: "I could go deeper on caching here, but let me first complete the architecture and we can return to it if useful."
If they want to spend more time on a particular topic, adapt and let the checkpoints slide.
The framework is not magic. It gives you a reliable path through ambiguity. Practice enough that the structure becomes automatic, then use the interview to reason about the specific system in front of you.