System Design Fundamentals
What is System Design?
ChatGPT feels like one box: type a message, expect the first tokens quickly, while millions of other sessions may be doing the same thing. The engineering is a map of pieces that must stay useful when traffic grows and machines fail.
System design is deciding how software pieces fit together so a product stays fast, reliable, and affordable as usage grows. You draw services, databases, queues, and caches, decide how data moves, and justify those choices with requirements and numbers.
Thinking loop
Product promise
What must stay true for users?
Traffic, size, peaks.
Simple shape
Fewest pieces that fit.
Stress + trade-off
What breaks, what you accept.
What actually happens as a product grows
A notes app on one laptop is mostly code. A notes app used by millions becomes a system: clients talk to APIs, APIs talk to stores, and slow work moves aside. You start caring about , , and because users feel those qualities directly.
Scaling tools appear when numbers force them. A spreads requests. A protects hot reads. A splits data that no longer fits one owner. None of these are decorations: each one answers a concrete pressure.
Distributed-systems ideas such as help you discuss tensions, but the daily skill is simpler: state the user promise, estimate load, draw a path, then revise when a bottleneck appears.
Try it: back-of-the-envelope QPS
Turn product language into numbers before you draw boxes. Daily actions become average queries per second; a peak multiplier models rush hour. Split reads and writes so you know which path saturates first.
Peak load vs a 1k QPS reference
Sizing hintA single app server and one database can often handle this with headroom if queries stay simple.
Adjust daily actions and peak multiplier. Average QPS spreads load across the day; peak QPS is what you size caches and databases for.
Say the formula out loud. Ten lakh reads per day is about twelve average QPS, but a 3× peak multiplier pushes planning toward thirty-five QPS. That gap is why interviews ask for both average and peak.
How to choose where to start
Once you see that growth forces new pieces, pick a starting path instead of memorizing every tool at once.
1. Practice one tiny design end-to-end. Requirements, rough math, one diagram, one bottleneck, one trade-off.
2. Learn components as jobs. Building Blocks owns the box catalog; this page owns the reasoning loop.
3. Prefer explanations over slogans. Say what quality improves and what quality gets worse, especially for , , and freshness.
Simple rule of thumb
Start with the user action and follow the bytes. If you can say where data is written, where it is read, and what fails first under load, you already understand the heart of system design.
Starter loop
Your first design in 10 minutes
After choosing where to start, practice one tiny product end to end. A useful first answer has one user flow, rough numbers, a simple diagram, one bottleneck, and one trade-off.
Time box
~2 min per step
- 1
Requirements
- 2
Estimates
- 3
Simple diagram
- 4
Bottleneck
- 5
Trade-off
Requirement
Users can create and read notes, so the scope stays concrete.
Estimate
Ten lakh reads per day is about twelve average QPS to size with.
Diagram
Client to API to database is enough for a first sketch.
Bottleneck
Peak reads may overload the database first, so name that bottleneck early.
Trade-off
Add a cache for speed, and accept briefly stale reads.
- 1
Requirements
Requirement
Users can create and read notes, so the scope stays concrete.
- 2
Estimates
Estimate
Ten lakh reads per day is about twelve average QPS to size with.
- 3
Simple diagram
Diagram
Client to API to database is enough for a first sketch.
- 4
Bottleneck
Bottleneck
Peak reads may overload the database first, so name that bottleneck early.
- 5
Trade-off
Trade-off
Add a cache for speed, and accept briefly stale reads.
Prerequisite map and how to read this page
After the 10-minute drill, use this map so you know what this page owns versus what Building Blocks owns. This page is the why and mental model: requirements, scale drivers, , , and distributed-systems vocabulary. For the component vocabulary (, , queue, boxes), read Building Blocks first or in parallel.
| If you know… | Start here | Then deepen with |
|---|---|---|
| Almost nothing yet | First design in 10 minutes + Numbers to know | Building Blocks, Approach |
| Basic CRUD apps | Requirements + user-count-is-a-proxy | Scaling, Caching, Load Balancing |
| Interview prep | Latency percentiles + trade-offs mindset | Trade-offs, Interview Framework |
| Distributed systems background | / + fallacies | Replication, CAP Theorem, Regionalisation |
How to read this page (beginner to advanced)
Beginner: Read the definition and scale idea. Treat and as simple tensions between correctness, uptime, and speed.
Intermediate: Connect scale rows to , , and . Read p50, p95, and p99 as user experience targets (see Numbers to know).
Advanced: Use failure domains and consistency trade-offs to reason about outages, data stores, team size, budget, and compliance.
Glossary quick hits: QPS (Queries Per Second) = traffic; SLA (Service Level Agreement) = promised uptime or latency to customers; partition = network break between machines so they cannot all talk; monolith = one big deployable app; microservice = smaller services talking over the network; fanout = one request triggering many downstream calls; idempotency = safe retries without duplicate side effects; blast radius = how much breaks when one component fails.
Thinking loop
A simple sequence of thinking
With the map and first drill in place, zoom out to the loop you will reuse on every problem. System design is not "draw the most complex architecture you know." It is: define the product promise, estimate the load, pick the simplest architecture that meets the promise, then stress it with scale and failure questions.
- 1
Product promise
Name the user promise that must stay true under load
- 2
Traffic & data estimates
Estimate rough QPS, data size, and peaks to size boxes
- 3
Core architecture
Pick the simplest architecture shape that still meets the promise
- 4
Failure & bottlenecks
Ask what breaks first when traffic spikes or machines fail
- 5
Trade-offs & iteration
Choose a trade-off deliberately, then revise the core when numbers shift
Loop → revise core architecture
Mental model
Architecture is a set of promises about latency, durability, freshness, cost, and operability.
Interviewers expect
Make assumptions explicit, then revise the design when numbers or constraints change.
Common pitfall
Listing components without saying which user problem or failure each one solves.
- 1
Product promise
Name the user promise that must stay true under load
- 2
Traffic & data estimates
Estimate rough QPS, data size, and peaks to size boxes
- 3
Core architecture
Pick the simplest architecture shape that still meets the promise
- 4
Failure & bottlenecks
Ask what breaks first when traffic spikes or machines fail
- 5
Trade-offs & iteration
Choose a trade-off deliberately, then revise the core when numbers shift
Loop back → revise core architecture
Mental model
Architecture is a set of promises about latency, durability, freshness, cost, and operability.
Interviewers expect
Make assumptions explicit, then revise the design when numbers or constraints change.
Common pitfall
Listing components without saying which user problem or failure each one solves.
Requirements: the first design material
Start with a concrete promise: a user can save a private note, close the browser, and open the same content from another device. This implies an authenticated write API, durable storage, and a read path that returns the right user’s data. “Support notes” is too vague to establish those requirements; describing the action makes the necessary behavior visible.
Then make quality measurable. For example, assume 95% of reads should finish within 200 milliseconds, acknowledged writes must survive one server failure, and other devices may see edits up to two seconds late. These are different requirements: the first concerns latency, the second durability, and the third freshness. Improving one does not automatically improve the others.
The thinking loop starts with a product promise. Requirements turn that promise into design material: whether you optimize for correctness, , cost, operability, or growth. Split them into functional (what users can do) and non-functional (how well the system must do it).
Functional
Functional requirements name actions and rules. In a notes app, creating, reading, editing, sharing, and deleting a note are distinct flows. Describe who may perform each action and what changes when it succeeds: sharing might create a permission record, while deletion might hide a note immediately and remove stored copies later. These details define the API and data model before any scaling choice.
Include the important failure behavior in the flow. If saving times out, the client needs to discover whether the save completed. If sharing fails, the original private note should remain accessible to its owner. Describing these outcomes makes the boundary of each operation clear.
Non-functional
Quality requirements put measurable limits around those actions. Estimate daily active users, read and write rates, peak bursts, record sizes, and retention so the design has a workload. Then specify latency, availability, durability, and freshness separately. A fast response from stale data may satisfy a latency target while violating the user’s expectation after an edit.
Operational constraints also shape the solution: budget, the team’s ability to run a database cluster, backup recovery time, and access controls. Record assumptions explicitly so a later change in traffic or product requirements leads to a reasoned revision instead of an unexplained architecture rewrite.
Interview phrase: "I will assume the core path is X, p95 latency target is Y, and we can tolerate Z seconds of staleness. If any of those are wrong, I would adjust the storage and caching choices."
Numbers to know
Requirements only become architecture when you attach numbers. This section holds the scale map, traffic-shape cues, percentiles, and downtime math so later sections can cross-reference instead of restating them.
System design at different scales
To turn users into load, suppose 100,000 daily active users each read 20 notes. That is 2,000,000 reads per day, or about 23 reads per second averaged over 86,400 seconds. A planning assumption of a tenfold peak gives about 230 reads per second. The assumption is provisional: an observed launch spike or a background import may be much larger. Also estimate writes separately because a write can consume different resources from a read.
User growth alone does not require a new architecture. A small number of users uploading large videos can exhaust bandwidth sooner than millions of users reading tiny cached documents. Use the table as a set of possible responses to measured pressure. A well-indexed database and a few application instances may remain appropriate long after the user count sounds impressive.
The architecture that serves 1,000 users is radically different from one that serves 1 billion. The "users" column is a rough mental anchor only. What really drives design is read/write traffic, data size, spike patterns, and consistency needs.
Column cheat sheet: Architecture = how application code is organized and deployed; Database = how primary data is stored and replicated; Caching = fast temporary storage to absorb reads or hot data; Infra = servers, regions, and orchestration complexity.
| Scale | Architecture | Database | Caching | Infra |
|---|---|---|---|---|
| 1K users | Single server monolith | Single relational DB | None needed | 1 VPS ($20/mo) |
| 10K users | Monolith + read replica | Primary + replica | App-level cache | 2-3 servers |
| 100K users | Vertical scaling + CDN | Sharded reads | Single cache node | Small cluster |
| 1M users | Microservices begin | Read replicas + cache | Cache cluster | Container orchestration |
| 10M users | Full microservices | Sharded DB cluster | Multi-layer | Multi-AZ |
| 100M users | Global distribution | Multi-region DB | CDN + cache cluster | Multi-region |
| 1B+ users | Custom infrastructure | Custom distributed storage | Edge + L1/L2/L3 | Global fleet |
Key inflection points (rules of thumb)
These thresholds vary by product. When numbers cross a line, name the next tool and explain why.
- ~10K users: add a and read replicas so one box is not the whole write and read path.
- ~100K users: add a dedicated layer so hot reads stop hammering the primary database.
- ~1M users: break the into services when team and release friction force ownership boundaries.
- ~10M users: plan and async queues so writes and heavy jobs leave the request path.
- ~100M users: plan multi-region designs when local outages or latency budgets span continents.
- ~1B users: expect custom infrastructure when commodity patterns no longer fit the workload.
User count is only a proxy
Same user count can need different systems. Traffic shape, data size, fanout, , and consistency decide the pressure.
- Read-heavy products lean on , , and read replicas to absorb repeated reads.
- Write-heavy products partition writes, use queues, and prefer append-only storage for continuous ingest.
- Storage-heavy products push large files into blob storage with lifecycle tiers and compaction for cost control.
- Latency-sensitive products tighten the p95 budget with local cache and fewer network hops on the critical path.
Latency percentiles and availability SLAs
is how long one request takes end-to-end. Throughput is how many requests per second the system can handle. Teams rarely report only the average: one slow dependency can make a few percent of requests awful while the average still looks fine. Track p50 (typical user), p95/p99 (tail pain), and tie them to product .
| Percentile | Meaning | Search Example |
|---|---|---|
| p50 (median) | 50% of requests are faster | 120ms (typical experience) |
| p95 | 95% of requests are faster | 250ms (most users fine) |
| p99 | 99% of requests are faster | 800ms (1 in 100 slow) |
| p99.9 | 99.9% of requests are faster | 2000ms (the "tail") |
Why p99 matters at billion-user scale: 1B requests/day × 1% = 10M slow requests/day. That is 10 million frustrated users.
An often states "available 99.9% of the year." Each extra "9" shrinks allowed downtime dramatically; engineering cost rises because you need redundancy, automation, and rehearsal for failures.
| SLA | Downtime/Year | Level |
|---|---|---|
| 99% | 3.65 days | Unacceptable |
| 99.9% | 8.76 hours | Startup-level |
| 99.99% | 52.6 minutes | Enterprise |
| 99.999% | 5.26 minutes | Critical platform target |
Business impact reminders (same idea as the hero, not new drama): +100ms can mean measurable sales loss on a large marketplace; +500ms can mean measurable traffic loss on a large search product.
Latency budget
Example: split a 200 ms target
The tables above give percentile and language. A budget splits the same user-visible target across the path so you can decide where hits, pooling, or async work matter.
User-visible target
200 ms
~20 ms headroom left for jitter, retries, and unexpected work. Database fallback is the biggest sync slice.
Client render
30 ms
Network
40 ms
API servers
40 ms
Cache lookup
10 ms
Database fallback
60 ms
Queue ack
20 ms
Off the user wait
- Client render30 ms
- Network40 ms
- API servers40 ms
- Queue ack20 ms
- Cache lookup10 ms
- Database fallback60 ms
Cache hit path
Client + network + API + cache ≈ 120 ms stays comfortable under 200 ms.
Cache miss path
Add the 60 ms DB fallback and the sync path climbs to ~180 ms.
Interview move
Say which steps stay sync for the user and which can move after acknowledgement.
How architecture evolves
A monolith describes a deployment boundary, not the number of servers: the same monolithic application can run on many machines behind a load balancer. Microservices separate deployment and ownership boundaries but add network calls, partial failures, and cross-service data coordination. Split a service when independent scaling, team ownership, or release isolation justifies that operational work. Merely adding users does not prove that a service split is needed.
Numbers to know show when pressure rises. This section shows common shapes teams move through as that pressure, team size, and ownership change. Products rarely jump straight to the most complex layout.
Single deployable unit. All code in one repository and process. Simple to develop, test, and deploy initially.
- Works well up to roughly fifty engineers before release coordination starts to hurt.
- Some large commerce products still run carefully managed monoliths at meaningful scale.
- Usually one shared database and memory space, which simplifies early transactions.
- Scale first by buying a bigger machine, then by running more identical copies behind a balancer.
Microservices
Independent services communicating over the network. Each team owns a service end-to-end.
- Large streaming platforms may run thousands of services with independent deploy cycles.
- Small service teams own interfaces end-to-end, which reduces cross-team merge friction.
- Services can deploy, scale, and fail independently, which shrinks some blast radii.
- You pay with network latency and harder distributed debugging across many hops.
Serverless / FaaS
Event-driven functions. No server management. Auto-scales from zero to millions of invocations.
- Managed function runtimes remove most server patching from the product team's plate.
- Pay per invocation instead of per idle hour, which fits bursty or sparse workloads.
- Cold starts can add about 100ms to 1s, so keep them off the tightest user paths.
- Best for event-driven and bursty workloads where idle capacity would otherwise waste money.
How large platforms evolve
Search platform pattern. Started with commodity hardware and custom infrastructure. Over time, teams built distributed file storage, batch processing, wide-column storage, and globally consistent databases. The key lesson is evolution: one architecture rarely serves both startup speed and global-scale reliability forever.
Streaming platform pattern. Migrated from a single monolithic app in owned infrastructure to many independently deployed services. The architecture needed API gateways, service discovery, circuit breakers, and failure injection because user-visible reliability depended on many networked components behaving well together.
Social graph platform pattern. Started as a web . As the social graph grew, teams added graph caches, distributed storage, typed API layers, specialized runtimes, and custom infrastructure. The main lesson is modeling hot relationships, fanout, and read-heavy access paths explicitly.
Marketplace platform pattern. A service-interface mandate forced teams to communicate through explicit APIs. This created strong ownership boundaries, but also required durable queues, object storage, key-value stores, and operational discipline across hundreds of services.
theorem and
Architecture evolution eventually puts data on multiple machines. That is when consistency, , and stop being slogans and become daily trade-offs.
Once data lives on multiple machines, networks can fail between them. During those failures, do you prefer to stop some requests until everyone agrees on the latest data (stronger consistency), or keep answering even if some reads are briefly stale ( + responsiveness)? gives vocabulary for that tension. adds: even when the network is fine, you still trade low vs strong consistency in normal operation.
In any distributed system, you can only guarantee two out of three properties simultaneously (this is a simplified teaching model; in practice, systems expose tunable knobs):
- C - Consistency: every read receives the most recent write so clients do not see conflicting answers.
- A - Availability: every request receives a response even when some replicas are hard to reach.
- P - Partition tolerance: the system keeps operating despite network failures between machines.
(extends CAP for real-world tradeoffs)
If Partition → choose Availability or Consistency (PAC). Else (normal operation) → choose Latency or Consistency (ELC).
| Database | Partition: A or C | Normal: L or C | Category |
|---|---|---|---|
| Highly available key-value store | A (available) | L (low latency) | PA/EL |
| Wide-column store | A (available) | L (low latency) | PA/EL |
| Document store | C (consistent) | L (low latency) | PC/EL |
| Globally consistent SQL store | C (consistent) | C (consistent) | PC/EC |
| Relational database | C (consistent) | C (consistent) | PC/EC |
Key insight: Most billion-user systems choose PA/EL ( + low ) and handle inconsistency at the application level with eventual consistency.
The trade-offs mindset
- Banking leans consistency so balances stay correct; social feeds often prefer availability with brief staleness.
- Real-time gaming needs low ; batch pipelines need high throughput instead.
- More regions raise and cost; see Numbers to know for how extra "9s" shrink downtime.
- A stays simpler to debug; microservices buy independent scale at the price of network complexity.
Distributed systems reality
The difficult failure is often uncertainty. A client sends a save request and times out; the server may have crashed before committing, or it may have committed and lost only the response. Retrying is necessary for progress but dangerous for non-idempotent work. Carry a stable operation identifier, record the result with the state change where possible, and return that result on a duplicate. This connects failure handling directly to API and data-model choices.
names the tension. The day-to-day reality is messier: no shared memory, unreliable networks, drifting clocks, and failure domains that grow from one server to a whole region.
Three fundamentals
- No shared memory: processes on different machines coordinate only by messages, so shared state needs explicit protocols.
- The network is unreliable: messages can be lost, delayed, duplicated, or reordered, so design for partial failure and idempotency.
- Clocks are not synchronized: machines drift, so prefer logical clocks or specialized global time when order must be correct.
The 8 fallacies of distributed computing
These false assumptions appear when engineers first build distributed systems. At large scale, each one becomes a design constraint.
- The network is reliable: packets get lost, and tiny failure rates become millions of failed calls at huge RPC volume.
- Latency is zero: cross-continent RTT is 100-300ms, and a 10-hop service chain can add another 50-200ms.
- Bandwidth is infinite: payload size matters, and compact binary formats can save petabytes versus chatty JSON.
- The network is secure: use zero-trust patterns such as mTLS, and encrypt data at rest and in transit.
- Topology does not change: servers come and go, orchestrators reschedule work, and discovery must track endpoints dynamically.
- There is one administrator: thousands of engineers may deploy independently across platform, reliability, and product layers.
- Transport cost is zero: serialization, compression, and encryption cost CPU, and one saved byte compounds daily.
- The network is homogeneous: different protocols, hardware, clouds, and hybrid deployments are normal in large enterprises.
Classic list from Deutsch, Gosling, and others (often called the "Fallacies of Distributed Computing"). Kleppmann's Designing Data-Intensive Applications expands partial failures, timeouts, and idempotent retries in production.
Infrastructure: regions, AZs, and blast radius
- Region: geographic area with multiple data centers, used for sovereignty and user-local latency.
- Availability Zone (AZ): independent data centers in a region; deploy across three AZs for high availability.
- Data center: often 50,000-100,000 servers with redundant power, cooling, and network paths.
Large global fleets may span 40+ DC locations across continents, 100K+ miles of private fiber, software-defined routing between sites, and 1M+ running servers.
| Failure | Impact | Mitigation |
|---|---|---|
| Server | 1 machine | Auto-replaced |
| Rack | 40+ servers | Replicate across racks |
| AZ | Thousands of servers | Replicate across AZs |
| Region | Millions of users | Multi-region architecture |
| Global | Rare | Graceful degradation, static pages |
Key takeaway
- System design means choosing pieces and data flow so the product stays useful as load and failures grow.
- Scale changes the architecture; use Numbers to know instead of memorizing every row twice.
- Track p50/p95/p99 , not averages, and tie uptime goals to an explicit .
- Evolve from toward services or serverless when traffic and team size force it.
- Most large systems lean PA/EL and handle inconsistency in the application carefully.
- Every choice is a trade-off: name what improves and what gets worse before you draw more boxes.
References
- Brewer: CAP twelve years later (partitions force consistency vs availability per operation)
- Abadi: PACELC (extends CAP with latency vs consistency in normal operation)
- Kleppmann: Designing Data-Intensive Applications (replication, consistency models, practical trade-offs)
- RFC 2119 (normative MUST/SHOULD language used in many distributed specs)
Practice and further reading
Use these exercises to connect the lesson to a design decision. State your assumptions, trace what happens to one request, and explain the rule that must remain true even during a failure. That rule is the design's correctness invariant.
Focus for this lesson: Run system design as an evidence-based decision process: clarify scope, quantify scale, choose contracts, protect invariants, and plan operations.
Explain the decision
What should happen in the first five minutes of an open-ended design interview?
Read the reasoning
Clarify actors, core operations, scale, latency/durability targets, exclusions, and the one or two correctness invariants before drawing infrastructure.
Apply it to a production scenario
The interviewer changes the requirement from regional availability to global active-active halfway through. How do you adapt?
Read one approach
Revisit write ownership, conflict policy, data residency, latency, and failover assumptions; preserve the original design as a simpler alternative and explain the delta.
Work through the numbers
Turn 20 million daily active users making 12 requests/day into average and 10x-peak QPS.
Read the worked calculation
240 million requests/day / 86,400 ≈ 2,778 average QPS; use about 27,800 QPS as the stated peak assumption.
Reason through a failure
What invariant anchors a payment-system discussion?
Read the recovery reasoning
A single business payment never creates two ledger effects, including across retries, timeout ambiguity, replay, and regional failover.
Sources and further study
Continue with Why Learn System Design?.