System design interviews separate senior engineers from the rest. This guide covers all 145 system design topics on TheCodeForge — from load balancing and caching to microservices and real-world architecture.
System design is the discipline of choosing which problems to have. Every architecture trades something away — consistency for availability, simplicity for scale, latency for durability — and the mark of a good design is not that it avoids trade-offs but that its author can name the ones they took and why.
That framing also explains why design questions have no answer key. Two competent engineers given the same requirements will produce different systems, and both may be right. What is not negotiable is knowing what each component costs you, because a cache, a queue and a replica all introduce failure modes that did not exist before you added them.
Before any component is chosen, four numbers determine the shape of the answer. How many requests per second, at peak rather than average. The read-to-write ratio. How much data, in total and per item. And how fresh the data must be.
Those four route you to a design almost mechanically. Read-heavy at 100:1 is a caching and replication problem. Write-heavy is a partitioning problem. Data that must be strongly consistent rules out the cheap availability tricks. Data measured in petabytes rules out anything that assumes a single primary.
| If the numbers say | The design is about | Not about |
|---|---|---|
| Read-heavy, tolerant of staleness | Caching, CDN, read replicas, denormalised read models | Sharding — you probably do not need it yet |
| Write-heavy, high volume | Partitioning, append-only storage, batching, back-pressure | Read caching, which will not help |
| Strong consistency required | A single authoritative writer per key, transactions, consensus where unavoidable | Multi-region active-active, which you cannot have cheaply |
| Spiky, unpredictable load | Queues, autoscaling, graceful degradation, rate limiting | Provisioning for peak, which wastes most of the time |
| Large media or files | Object storage plus CDN, signed URLs, async processing | Storing bytes in the primary database |
CAP is routinely misquoted as 'pick two'. The accurate statement is narrower and more useful: when a network partition occurs, a distributed system must choose between remaining available and remaining consistent. Partitions are not optional — they are a property of networks — so the real choice is what happens during one.
The more practically relevant extension is PACELC: even when there is no partition, there is a trade between latency and consistency. Every synchronous replication decision is an instance of it. That is the version worth carrying into design discussions, because partitions are rare and the latency trade is continuous.
A short vocabulary covers most designs, and each entry is worth knowing with its cost attached rather than as a name to drop.
| Pattern | Buys you | Costs you |
|---|---|---|
| Cache-aside | Large read speedup for hot keys | Staleness, invalidation logic, thundering herd on expiry |
| Message queue | Decoupling, spike absorption, retries | Eventual consistency, ordering questions, a dead-letter queue someone must own |
| Read replicas | Read scale with no application redesign | Replication lag — a user may not see their own write |
| Sharding | Write scale past one primary | No cross-shard joins or transactions; resharding is painful |
| Circuit breaker | Fast failure instead of cascading timeouts | Requires sensible thresholds and a half-open recovery path |
| Idempotency keys | Safe retries for non-idempotent operations | Storage and expiry for the key set |
| CDN | Latency close to the user, origin offload | Cache invalidation across edges; not for personalised content |
At any real scale something is always broken. The design question is not how to prevent failure but how the system behaves during it. Timeouts on every network call, because a call without a timeout is a resource leak waiting for a slow dependency. Retries with exponential backoff and jitter, because synchronised retries are how a brief blip becomes an outage. Circuit breakers so a slow dependency fails fast instead of consuming every thread.
And graceful degradation: decide in advance which features may be switched off to keep the core working. A product page that renders without recommendations is a far better outcome than one that does not render at all, and that is a design decision made before the incident, not during it.
Every tutorial starts with a plain-English analogy — then real code, then interview questions.
Browse System Design Tutorials →