Every system design problem — no matter how large — is built on one humble interaction: a client asks a server for something, and the server answers. Netflix, your bank, and a weekend side-project all start here. Master this round trip and the rest of the curriculum is just scaling it up.
Use the canvas on the right to step through a single request. Press Play, or use Next / Back to move one hop at a time.
The cast of characters
Client
The thing that initiates a request — usually a browser or mobile app. It knows what it wants (a web page, some JSON) but not yet where the server lives.
DNS (Domain Name System)
The internet's phone book. It translates a human name like example.com into an IP address like
93.184.216.34 that computers can actually route to. DNS is hierarchical: your OS checks a local
cache first, then a recursive resolver, then authoritative name servers.
Server
A program, running on a machine somewhere, that listens for requests and returns responses. In this first lesson it's a single monolith — one process that does everything.
Database
Where the server keeps data that must outlive a single request: users, posts, orders. The server queries it to build each response.
What actually happens when you load a page
Follow along with the animation:
- DNS lookup — the browser can't connect to a name, only to an IP. It asks a DNS resolver to look up
example.com. - DNS answer — the resolver replies with the IP address. (In reality this is cached aggressively — more on that in Chapter 4.)
- HTTP request — the browser opens a connection to that IP and sends
GET /. - The server does work — to build the page it queries the database for the data it needs.
- The database responds — it returns the matching rows.
- HTTP response — the server renders HTML and replies
200 OK. The browser paints the page.
Notice there are really two round trips hiding here: browser ↔ DNS, then browser ↔ server. Each round trip costs latency. A huge amount of system design is about removing round trips — with caching, CDNs, and keeping connections open.
The 4-step interview framework
The biggest mistake in a system design interview is jumping straight to solutions. The process matters more than the answer. Follow this framework:
- Understand the problem — ask clarifying questions before drawing anything. "Is this mobile, web, or both? How many daily active users? What are the most important features?" A candidate who starts designing without asking questions signals poor judgment.
- Propose a high-level design — draw the boxes: clients, APIs, servers, databases, caches, CDN. Walk through a few concrete use cases. Do rough back-of-the-envelope estimates to check if your design fits the constraints.
- Design deep dive — zoom into the interesting parts (the ones the interviewer cares about). This is where you show depth: how the cache is invalidated, how the database handles scale, what happens on failure.
- Wrap up — briefly discuss what you'd improve with more time: rate limiting, monitoring, edge cases, operational concerns.
Don't be "like Jimmy" — the student who jumps to answer before thinking. In system design, giving an answer quickly without understanding requirements is a red flag. Slow down, ask questions, write down your assumptions. The interviewer is evaluating your process, not just your answer.
Before HTTP: the TCP handshake
Before any HTTP data flows, the client and server complete a three-way TCP handshake (SYN → SYN-ACK → ACK). For HTTPS, a TLS handshake layers on top: the server presents its certificate, they agree on a cipher suite, and keys are exchanged. Together these add 1–3 round trips before your first byte of data. This is why:
- HTTP keep-alive (persistent connections) — reuse the same TCP connection for multiple requests instead of reconnecting each time
- HTTP/2 — multiplexes many requests over a single connection simultaneously, eliminating head-of-line blocking
- HTTP/3 (QUIC) — runs over UDP to cut handshake latency further; no TCP handshake at all
Latency numbers every engineer should know (Dr. Jeff Dean, Google):
| Operation | Latency |
|---|---|
| L1 cache reference | 0.5 ns |
| Main memory (RAM) access | 100 ns |
| SSD random read | 150 µs |
| Spinning disk seek | 10 ms |
| Send 1 KB over 1 Gbps network | 10 µs |
| Same datacenter round trip | ~0.5 ms |
| Cross-region (US) round trip | ~50 ms |
| US → Europe round trip | ~150 ms |
Memory is ~100,000× faster than disk. A cache miss to disk costs as much as 20 cross-datacenter round trips. These numbers justify every caching and replication decision you'll ever make.
HTTP status codes you must know
| Code | Meaning | Design implication |
|---|---|---|
| 200 | OK | Standard success |
| 201 | Created | After a successful POST |
| 301 | Moved Permanently | Client caches the redirect forever |
| 302 | Found (Temporary Redirect) | Client re-checks next time |
| 400 | Bad Request | Client-side error; don't retry blindly |
| 401 | Unauthorized | Need credentials |
| 429 | Too Many Requests | Rate limiting; client should back off |
| 500 | Internal Server Error | Server-side fault; retry with backoff |
| 503 | Service Unavailable | Overloaded/down; use circuit breaker |
Request / response is the atom
This single pattern — request in, response out — is the atom everything else is made of. A load balancer sits between client and server. A cache short-circuits the trip to the database. A CDN moves the server closer to the user. None of it changes the fundamental shape: someone asks, something answers.
When an interviewer says "design Twitter", don't jump to databases. Start by drawing this exact picture — client, server, database — and say out loud: "Let's begin with the simplest thing that works, then find where it breaks." Establishing the naive design first signals senior judgment and gives you a baseline to scale from.
Stateless vs. stateful servers
A stateless server treats each request independently — every request carries everything the server needs (an auth token, the user ID). A stateful server keeps session memory between requests.
Stateless is almost always the better default for web servers because:
- Any server can handle any request (necessary for horizontal scaling)
- No server-specific session data to lose on crashes
- Load balancers can freely route requests
Session state (shopping carts, auth tokens) gets pushed to a shared external store — typically Redis — where every server instance can reach it.
Where the traffic comes from: web vs. mobile
The same server tier usually answers two very different kinds of clients, and naming both signals that you understand the full surface area:
| Client | What runs where | Wire format |
|---|---|---|
| Web application | Server-side language (Java, Python, …) handles business logic and storage; client-side HTML + JavaScript handles presentation | Server returns rendered HTML |
| Mobile application | All UI is native on the device; the server is just an API | HTTP requests, JSON responses |
For mobile (and increasingly for web SPAs), the server stops returning HTML and instead exposes a JSON API. JSON is the common response format because of its simplicity. A request looks like:
GET /users/12 → retrieves the user object for id = 12
Both clients speak the same protocol — HTTP — to the same web tier. The difference is only what the server hands back: a fully rendered page for a browser, or a serialized object for an app to render itself. This is why a single API tier can serve web, iOS, and Android at once.
SQL vs. NoSQL: which database to reach for
Once the database is its own tier, the first real decision is which kind. There are two families, and an interviewer will expect you to justify your pick rather than default blindly.
Relational database (RDBMS / SQL)
Stores data in tables and rows and lets you combine tables with JOIN operations in SQL.
MySQL, PostgreSQL, and Oracle are the popular ones. They've been proven for 40+ years and are
the right default for most applications.
NoSQL (non-relational) database
Drops the rigid table model — and usually JOINs along with it — in favor of scale and
flexibility. Comes in four families: key-value stores (Redis, DynamoDB), graph stores
(Neo4j), column stores (Cassandra, HBase), and document stores (CouchDB, MongoDB).
Relational is the safe default. Reach for NoSQL only when one of these is true:
- Your application requires super-low latency.
- Your data is unstructured, or you have no relational data at all.
- You only need to serialize and deserialize data (JSON, XML, YAML).
- You need to store a massive amount of data.
Say: "I'd start with a relational database — they're 40-plus years proven and JOINs make the data model easy. I'd only move to NoSQL if we needed super-low latency, the data were unstructured, or the volume got large enough that a single relational schema couldn't keep up." Defaulting to Postgres with a stated reason to switch reads as far more senior than reflexively reaching for "web scale" NoSQL.
Logging, metrics, and automation are first-class
At a handful of users you can ignore operations. At scale, observability and automation are part of the design, not an afterthought — and mentioning them is exactly the "wrap up" move the framework asks for.
Logging — capture error logs so you can spot and diagnose problems. At scale, logs are aggregated to a centralized service rather than read box-by-box.
Metrics — collected at three levels, each answering a different question:
| Level | Examples | Answers |
|---|---|---|
| Host-level | CPU, memory, disk I/O | Is this machine healthy? |
| Aggregated | Performance of the whole database tier, the whole cache tier | Is this layer healthy? |
| Key business | Daily active users (DAU), retention, revenue | Is the product healthy? |
Automation — as the system grows, build tooling to keep it productive: continuous integration (CI) so every code check-in is verified by automated builds and tests, and automated continuous delivery (CD) for the build, test, and deploy pipeline.
In wrap-up, say: "I'd add logging, metrics at the host, tier, and business level, and a CI/CD pipeline so deploys are automated and safe." Naming the three metric levels — and distinguishing host health from business health like DAU and revenue — shows you've operated a system, not just drawn one.
Why the monolith eventually hurts
One server is wonderfully simple: easy to deploy, easy to reason about. But it has a ceiling. As traffic grows, that single box runs out of CPU, memory, and connections — and if it dies, your whole product is down. There is no redundancy.
That tension — simplicity now versus the wall you'll hit later — is the engine of this entire course. In Chapter 2 we hit the wall and learn the two ways out: make the box bigger, or add more boxes.
Interviewers often ask "how many servers do you need?" before you've said much about the design. The right response is to do a quick back-of-the-envelope estimate: how many requests per second, how long each takes, how much RAM per request. A single modern server can handle ~10,000–50,000 lightweight HTTP requests per second. That number anchors the scaling conversation.
Practice
Answer these to check you understood the page-load round trip.
1. What is the job of DNS?
2. Why does one single server become risky as traffic grows?
3. A 'stateless' web server means:
4. How many round trips happen in the basic page load above?