System Design
System design is the process of defining the architecture, components, modules, interfaces, and data for a system to satisfy specified requirements. It sits at the intersection of computer science fundamentals, engineering pragmatism, and product constraints.
In interviews, system design questions are intentionally ambiguous. The interviewer wants to see how you reason through tradeoffs, communicate assumptions, and evolve a design from a whiteboard sketch to a production-ready architecture. There is rarely a single correct answer — there are only answers that satisfy constraints better or worse.
This tutorial series walks through the core pillars of distributed system design: scalability, databases, caching, microservices, APIs, reliability, security, messaging, and the CAP theorem. It closes with two full case studies — a URL shortener and a real-time chat system — that demonstrate how the pieces fit together.
Every successful product eventually faces the same class of problems: traffic grows 10x overnight, a database becomes a bottleneck, a third-party API goes down, or a security incident exposes customer data. Good system design anticipates these failure modes and builds in margins for growth.
Beyond interviews, system design is the daily work of senior engineers. Choosing between SQL and NoSQL, synchronous and asynchronous communication, strong and eventual consistency — these decisions compound into the quality, cost, and operability of the final product.
| Concern | Poor Design | Good Design |
|---|---|---|
| Scalability | Single server that saturates at peak | Horizontally scalable, stateless tier |
| Reliability | Cascading failures, no retries | Circuit breakers, bulkheads, graceful degradation |
| Maintainability | Tightly coupled monolith | Bounded contexts, clear interfaces |
| Cost | Over-provisioned idle capacity | Auto-scaling, spot instances, caching |
| Security | Perimeter-only trust model | Zero trust, least privilege, encryption |
info
A structured approach keeps the interview focused and demonstrates senior-level thinking. The framework below is used by engineers at top technology companies and maps cleanly to real-world design processes.
1. Understand Requirements
Clarify functional requirements (what the system must do) and non-functional requirements (latency, throughput, availability, consistency). Ask about scale: daily active users, read/write ratios, data volume, and geographic distribution.
2. Define Constraints
Identify budget, team size, compliance needs, latency budgets, and existing tech stack. Constraints shape every subsequent decision more than raw theory does.
3. Back-of-the-Envelope Math
Estimate QPS, storage, bandwidth, and cache size. Numbers validate whether a proposed design can plausibly meet requirements and expose hidden bottlenecks.
4. High-Level Design
Sketch the system in 5-10 minutes: clients, load balancers, application servers, databases, caches, and message queues. Keep it simple enough to explain in a single narrative.
5. Deep Dives
Drill into the most uncertain or critical components. Common topics include data partitioning, replication, caching strategy, consistency models, and failure handling.
6. Tradeoffs and Alternatives
Discuss what you are giving up for each choice. Interviewers reward self-awareness: knowing when a design is wrong for a different set of constraints is as valuable as knowing why it is right for the current ones.
best practice
Functional requirements describe behavior. They are usually verbs: post a tweet, shorten a URL, send a message, process a payment. Non-functional requirements describe qualities: the system must serve 99.9% of requests under 100 ms, must survive a single data-center failure, or must encrypt data at rest.
| Type | Examples | Why It Matters |
|---|---|---|
| Functional | Create account, upload photo, fetch feed | Defines API surface and data model |
| Scalability | 1M DAU, 10K writes/sec, 100K reads/sec | Drives sharding, caching, and load balancing |
| Availability | 99.99% uptime, RTO < 1 hour | Requires redundancy and runbooks |
| Latency | p99 < 200 ms for reads | Pushes data closer to users via CDN/cache |
| Consistency | Payments: strong; likes: eventual | Influences database and replication choices |
| Durability | Zero data loss for committed writes | Requires replication, backups, and WAL |
warning
Capacity estimation turns vague scale targets into concrete numbers. The goal is not precision; it is order-of-magnitude correctness. Use round numbers and justify assumptions.
| 1 | Example: Design a URL shortener for 100M monthly active users. |
| 2 | |
| 3 | Assumptions: |
| 4 | - 10% of MAU create a short URL daily = 10M writes/day |
| 5 | - Each shortened URL is read 100 times/day = 1B reads/day |
| 6 | - Average slug length: 7 bytes; metadata: 500 bytes/row |
| 7 | - Peak traffic = 5x average |
| 8 | |
| 9 | Writes per second: 10M / 86,400 ≈ 116 writes/sec (peak ≈ 580) |
| 10 | Reads per second: 1B / 86,400 ≈ 11,574 reads/sec (peak ≈ 57,870) |
| 11 | Daily new storage: 10M rows × 507 bytes ≈ 4.7 GB/day |
| 12 | Yearly storage: 4.7 GB × 365 ≈ 1.7 TB/year (raw) |
| 13 | With 3x replication: ≈ 5.1 TB/year |
These numbers immediately tell you that reads dominate writes, so a caching layer is essential. They also tell you that a single relational database could handle the write volume but would struggle with the read volume without replicas or a cache.
pro tip
The high-level design is a conceptual map of the system. It should be technology-agnostic at first — talk about load balancers, application servers, caches, databases, and queues before naming specific products. Once the shape is agreed upon, you can substitute concrete technologies.
| 1 | ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ |
| 2 | │ Client │────▶│ CDN │────▶│ Load Balancer │ |
| 3 | │ (Browser) │ │ (Static) │ │ (Round-Robin/L7) │ |
| 4 | └─────────────┘ └─────────────┘ └──────────┬──────────┘ |
| 5 | │ |
| 6 | ┌────────────────────────┼────────────────────────┐ |
| 7 | │ │ │ |
| 8 | ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ |
| 9 | │ App Server │ │ App Server │ │ App Server │ |
| 10 | │ (Stateless)│ │ (Stateless)│ │ (Stateless)│ |
| 11 | └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ |
| 12 | │ │ │ |
| 13 | └──────────────┬─────────┴──────────┬─────────────┘ |
| 14 | │ │ |
| 15 | ┌──────▼──────┐ ┌──────▼──────┐ |
| 16 | │ Cache │ │ Queue │ |
| 17 | │ (Redis) │ │ (Kafka) │ |
| 18 | └──────┬──────┘ └──────┬──────┘ |
| 19 | │ │ |
| 20 | ┌──────▼──────┐ ┌──────▼──────┐ |
| 21 | │ Database │ │ Workers │ |
| 22 | │(Primary/Rep)│ │ (Async) │ |
| 23 | └─────────────┘ └─────────────┘ |
This canonical layered architecture separates concerns: the CDN handles static assets and edge caching, the load balancer distributes traffic, stateless app servers hold no session data, the cache absorbs hot reads, the database is the source of truth, and the queue decouples heavy work.
note
After the high-level design, the interviewer will push on the weakest or most interesting parts of the system. Typical deep-dive topics include data modeling, sharding strategy, cache invalidation, consistency guarantees, and failure scenarios.
| Component | Common Questions | Key Techniques |
|---|---|---|
| Database | How do you scale writes? Handle hot shards? | Sharding, replication, indexing, partitioning |
| Cache | What happens on a cache miss? How do you keep data fresh? | Cache-aside, write-through, TTL, invalidation |
| Load Balancer | How do you route sticky sessions? Detect failures? | Health checks, consistent hashing, least-connections |
| Message Queue | What if a consumer crashes? How do you order events? | Idempotency, at-least-once, partitions, offsets |
| API | How do you version? Prevent abuse? | Versioned routes, rate limiting, idempotency keys |
best practice
Every design decision is a tradeoff. The hallmark of a senior engineer is the ability to articulate what is gained and lost. Do not present choices as universally good or bad; present them as context-dependent.
| Tradeoff | Option A | Option B | When to Choose |
|---|---|---|---|
| SQL vs NoSQL | Strong consistency, joins | Horizontal scale, flexible schema | SQL for relational data; NoSQL for high-write/scale |
| Sync vs Async | Simpler, stronger consistency | Decoupled, resilient, higher throughput | Sync for user-facing critical paths; async for background work |
| Strong vs Eventual | Correctness, complexity | Availability, lower latency | Strong for financial data; eventual for social counters |
| Monolith vs Microservices | Simpler deployment, lower overhead | Independent scale, team autonomy | Monolith for small teams; services for large orgs |
info
The following pages explore each pillar in depth. Read them in order if you are new to system design, or jump to the topics most relevant to your interview or project.
pro tip