system-design

What Is System Design?

The discipline of deciding how the pieces of software fit together, under constraints you did not choose, to serve people you will never meet.

Prerequisites: none Time to read: ~12 minutes


Start with something you’ve already built

You built a to-do app. Maybe in a university project, maybe a tutorial. It had:

That is a system. You already did system design — you just did it for one user (you), on one machine, with zero money at stake, and nothing bad happened when it broke.

System design is what happens when you remove those four gifts.

Your to-do app The real world
1 user 40 million users
One machine 2,000 machines in 5 countries
Restart when broken Breaking costs $50,000/minute
Data loss = whatever Data loss = lawsuit
Latency = instant (localhost) User in Karachi, server in Virginia: 250 ms round trip minimum
You own everything Twelve teams own pieces of it

Every technique in this repository exists because one of those columns turned into the other.


A concrete example: the moment design starts to matter

Here is your to-do app’s “get my tasks” endpoint:

@app.get("/tasks")
def get_tasks(user_id):
    return db.query("SELECT * FROM tasks WHERE user_id = ?", user_id)

On your laptop this returns in 3 milliseconds. Ship it. Now watch it die, one step at a time.

Day 1 — 100 users. Works perfectly. Nothing to do.

Day 30 — 10,000 users. Some queries take 800 ms. Why? The tasks table has 2 million rows and there is no index on user_id, so the database scans every row on every request. → You need Indexing.

Day 90 — 200,000 users. The single server is at 100% CPU. Every request queues behind others. → You need Horizontal Scaling and a Load Balancer.

Day 120. Now there are 5 servers, but user sessions were stored in each server’s memory, so users get logged out randomly depending on which server they hit. → You need Stateless Services and a shared session store.

Day 180 — 2 million users. The database is now the bottleneck; 5 app servers all hammer one PostgreSQL instance. Reads are 95% of traffic. → You need Read Replicas and a Cache.

Day 240. A celebrity user with 400,000 shared tasks makes one cache key so hot that the Redis node serving it saturates its network card. → You need to understand Hot Keys.

Day 365 — 40 million users. One database can no longer hold the data. → You need Sharding, which forces you to give up cross-user joins and transactions, which changes your product.

Day 400. You expand to Dubai and Singapore. A user in Dubai waits 300 ms for every request because the database is in Virginia. → You need Multi-Region — and now you must choose between consistency and latency, which is CAP/PACELC.

Day 450. A network partition between regions means two users edit the same task in two regions simultaneously. Which write wins? → You need Conflict Resolution.

Notice what happened. Nothing about the feature changed. “Show me my tasks” is the same product requirement on day 1 and day 450. Everything that changed was scale, geography, money, and failure — and each of those forced a design decision with a cost attached.

That is the whole field. That’s it. You are learning the ordered list of things that break, and what to do about each one.


The four questions every design answers

Whatever the system, you are always answering the same four questions:

1. What does it need to do? (Functional requirements)

“Users can post a tweet. Followers see it in their feed.” Concrete behaviours.

Most candidates rush this. Most interviews are lost here — because if you design the wrong system beautifully, you still designed the wrong system. → Requirements Gathering

2. How well does it need to do it? (Non-functional requirements)

These constraints do more to determine the architecture than the features do. A chat app that tolerates 2 seconds of delay and a trading system that requires 2 microseconds are the same feature and completely different systems.

3. What are the pieces, and how do they talk?

Servers, databases, caches, queues, load balancers. The boxes-and-arrows diagram. This is what people think system design is. It’s about 25% of it.

4. What breaks, and what happens when it does?

The disk fills. The network partitions. A deploy goes bad. A downstream service takes 30 seconds instead of 30 milliseconds. Traffic goes 10× in one minute because of a TV ad.

Senior engineers are distinguished almost entirely by how much time they spend on question 4. Juniors design the happy path. Seniors design the failure path.


🧠 Mental model: designing a restaurant

You are opening a restaurant. Not writing code — running a kitchen.

Restaurant System
Customers Users / clients
Host at the door seating people at tables Load balancer
Waiters taking orders API servers
Kitchen cooking food Backend services / workers
The order rail where tickets hang Message queue
Pantry and walk-in freezer Database
Pre-made sauces on the line Cache
A second identical kitchen in another city Multi-region
Menu API contract
Chef shouting “86 the salmon!” Circuit breaker
A tour bus arrives unannounced Traffic spike / thundering herd
Health inspector Monitoring

Now the design questions become obvious, and they’re the same ones:

You already have intuitions about restaurants. This entire repo is teaching you the same intuitions about computers — plus the arithmetic to prove which choice is right.


What system design is not

It is not memorizing architectures. “Twitter uses fan-out on write” is a fact. Knowing why they chose it, when it breaks (celebrities with 100M followers), and what they do instead (hybrid fan-out) is design. Interviewers can tell the difference in about ninety seconds.

It is not choosing the newest technology. Reaching for Kubernetes, Kafka, and a microservice mesh to serve 500 users is a negative signal. The correct answer to many problems is “one Postgres instance and a cache.”

It is not knowing every tool. You need to know maybe fifteen categories of component and their trade-offs. Whether the queue is SQS, RabbitMQ, or Kafka matters far less than knowing you need a queue and what it buys you.

It is not one right answer. There is no answer key. There are defensible designs and indefensible ones. “It depends” is a legitimate opening — as long as the next sentence is “and here is what it depends on.”


Why it’s on every interview loop

Companies do not run design interviews to check whether you’ve read a book. They run them because the interview is a cheap simulation of the job:

The interview tests Because on the job you must
Do you ask what the problem is before solving it? Product specs are always ambiguous
Can you estimate? Decide if something needs 3 servers or 300, before building it
Do you reason about trade-offs or recite? Every real decision has a cost
Do you handle failure? Everything fails, constantly
Can you explain your thinking clearly? You have to convince a team
Do you know when to stop? Over-engineering wastes months

That last row surprises people. Proposing a simpler design and justifying why the complex one isn’t needed yet often scores higher than the complex design.


🚨 What beginners get wrong on day one


🎙️ Soundbites


🛠️ Try it

Take an app you use daily — WhatsApp, Careem, Instagram, your university portal. Spend 15 minutes writing down, in plain English:

  1. Three things it must do.
  2. What “too slow” would feel like, in milliseconds.
  3. One thing that would be catastrophic if it failed, and one thing that would just be annoying.
  4. One place you suspect the data is not instantly consistent everywhere. (Hint: like counts.)

Keep this note. Re-read it after Week 6 of the roadmap. The difference in what you notice is the measure of your progress.


Check yourself

1. Your app works fine at 1,000 users and falls over at 100,000. Name three completely different things that could be the bottleneck. Database CPU (unindexed queries or too many connections), application server CPU/memory (single instance saturated), and network/bandwidth limits. Also: connection pool exhaustion, a single-threaded component, disk IOPS, or an external API rate-limiting you. The point is that "it's slow" is never an answer — you must localize it. See [Finding Bottlenecks](/system-design/10-performance/01-finding-bottlenecks.html).
2. Why is "we'll use microservices" a bad opening statement in a design interview? Because it's a solution before a problem. Microservices solve *organizational* scaling (many teams shipping independently) at the cost of operational complexity, network failures between every call, and distributed transactions. If the interviewer hasn't told you there are 200 engineers, you've imported a large cost for no stated benefit. See [Monolith vs Microservices](/system-design/05-architecture-patterns/01-monolith-vs-microservices.html).
3. Give an example where showing stale data for 10 seconds is fine, and one where it's a disaster. Fine: a YouTube view counter, a Twitter like count, a "trending" list. Disaster: your bank account balance right before you authorize a transfer, seat availability in a ticket sale, or an inventory count during a flash sale (you'll oversell). This is why [consistency models](/system-design/01-foundations/13-consistency-models.html) are a per-feature decision, not a per-system one.
4. What's the difference between a functional and a non-functional requirement? Functional = *what it does* ("a user can upload a video"). Non-functional = *how well* ("uploads up to 4 GB, playback starts within 2 s, available 99.95% of the time, videos never lost"). The non-functional requirements are what actually drive the architecture.
5. Why do senior engineers spend so much time on failure cases? Because at scale, rare events are constant. If a disk fails once per 3 years and you have 10,000 disks, you lose roughly 9 disks a day. Anything that *can* happen *is* happening right now, somewhere in your fleet. Designs that assume success are designs that assume a fleet of one. See [Failure Modes](/system-design/04-distributed-systems/02-failure-modes.html).

Further reading