System Design
How to design a system that handles real traffic — the building blocks, the trade-offs, and a repeatable method for working through an unfamiliar problem
Algorithm problems have one right answer. System design does not.
Ask ten engineers to design a photo-sharing service and you will get ten different diagrams, several of them good. What separates a strong design from a weak one is not the boxes — it is whether the person can explain why each box is there, what it costs, and what breaks when traffic grows ten times.
That is what this section teaches.
What You Are Actually Being Asked
A design question is deliberately vague. "Design a URL shortener" tells you almost nothing: how many users, how fast, read-heavy or write-heavy, does it need analytics?
The vagueness is the point
A well-specified problem tests whether you can code. A vague one tests whether you can find the important questions before answering.
The first five minutes should be spent narrowing the problem, not drawing. A design built on unstated assumptions is a design nobody can evaluate — including you.
The Method
Every problem in this section is worked with the same six steps. Follow them in order and an unfamiliar problem becomes a familiar procedure.
Clarify and scope
Ask what the system must do and, just as importantly, what it need not do. Write down the two or three features you will actually build.
"Shorten a URL and redirect. No custom aliases, no analytics, no expiry. Agreed?"
Put numbers on it
Estimate reads per second, writes per second, and storage growth per year. You are not aiming for accuracy — you are aiming for the order of magnitude, because that is what decides the architecture.
100 writes per second and 100,000 writes per second are different systems.
Define the interface
Name the handful of operations the system exposes. Two or three endpoints is usually enough.
This is where you notice a design is doing too much.
Sketch the simplest thing that works
One service, one database. No cache, no queue, no sharding.
Starting simple is not naive — it gives you a baseline to improve, and it shows you understand that complexity must be earned.
Find the bottleneck, then fix that one thing
Look at your numbers and ask what breaks first. Add exactly one component to fix it. Then ask again.
Each addition should answer a specific pressure you have already named.
Say what you traded away
Every choice costs something. A cache adds staleness. A queue adds delay. Sharding makes joins hard.
Naming the cost is the single clearest signal that you understand your own design.
The most common mistake
Drawing the final architecture immediately — load balancer, cache, sharded database, message queue, CDN — before any numbers exist.
It looks impressive and it is hollow. If you cannot say what pressure each component relieves, the design is memorised, not reasoned. Someone will ask "why the queue?" and there will be no answer.
Start simple. Add under pressure. Always.
From Simple to Scaled
Here is the shape almost every design follows. The point is not that the final picture is correct — it is that each step is caused by the previous step's limit.
What This Section Covers
Foundations — the building blocks
Each explains one component and, more importantly, what it costs.
Numbers Every Design Needs
Latency figures, capacity estimation, and turning 'a million users' into requests per second
Networking Basics
DNS, TCP vs UDP, the HTTP versions, TLS, and what a CDN actually does
Scaling
Vertical vs horizontal, why stateless matters, and load balancing
Caching
Where to put a cache, eviction, invalidation, and the three failure modes
Databases
SQL vs NoSQL, indexing, replication, and sharding
Storage Engines
Object vs block vs file, and the B-tree / LSM-tree split
Partitioning and Consistent Hashing
Splitting data without reshuffling it, plus geohashing for location
Consistency and CAP
What you give up when data lives in more than one place
Distributed Primitives
Leader election, consensus, distributed locks, and logical clocks
Queues and Async Work
Decoupling, back pressure, delivery guarantees, and idempotency
APIs and Rate Limiting
Endpoint design, pagination, idempotency keys, and protecting the system
Services and Boundaries
Monolith vs services, where to draw lines, and the machinery it costs
Search Systems
The inverted index, tokenisation, ranking, and index freshness
Probabilistic Structures
Bloom filters, HyperLogLog and count-min sketch — accuracy traded for memory
Security
Authentication vs authorisation, tokens, encryption, and the attacks to design against
Reliability
Failure is normal — timeouts, retries, circuit breakers, degradation
Observability
Logs, metrics and traces, and defining what 'working' means
Deployment and Migrations
Canary releases, feature flags, and changing a schema without downtime
Worked Designs
Each applies the six steps end to end, and ends with what it traded away.
URL Shortener
ID generation, read-heavy traffic, and the redirect path
Rate Limiter
Four algorithms compared, and the distributed counting problem
Distributed Key-Value Store
Consistent hashing, quorums, and resolving conflicting writes
News Feed
Fan-out on write vs on read, and why celebrities break both
Chat System
Long-lived connections, delivery guarantees, and message ordering
Notification System
Push, email and SMS at scale, and not driving users to opt out
Search Autocomplete
Tries at scale, ranking, and serving suggestions in under 100ms
Web Crawler
Deduplicating billions of URLs, politeness, and avoiding traps
File Storage and Sync
Chunking, deduplication, delta sync, and conflict resolution
Ride Sharing
Geospatial indexing, 250k location writes/sec, and matching races
Ticket Booking
Never double-booking a seat, and surviving a 100,000:1 traffic spike
Payment System
Idempotency, the double-entry ledger, and reconciliation
Video Streaming
Transcoding pipelines, adaptive bitrate, and moving bytes close to users
How to Read This Section
Read the foundations first, then one worked design
The foundation pages each explain one building block and, more importantly, what it costs. The worked designs then assemble those blocks under pressure.
Reading a worked design without the foundations gives you a diagram to memorise. Reading the foundations first gives you the ability to derive the diagram — which is the actual skill.
There is no code in this section. System design is about trade-offs between components, not implementations, and a page full of code would hide that.