System design interview cheat sheet
Most system design interview advice is a list of buzzwords — “use a cache,” “add a load balancer,” “shard the database.” That’s not a framework, it’s a vocabulary list, and interviewers can tell the difference immediately. This page gives you a repeatable process for approaching any system design question, a reference for the trade-offs you’ll actually be asked to reason about, and one fully worked example so you can see the framework applied end-to-end rather than just described in the abstract.
The framework: a 7-step process for any system design question
Use this structure every time, regardless of what you’re asked to design. Interviewers are evaluating your process as much as your final answer — skipping steps (especially requirements clarification and capacity estimation) is the single most common reason otherwise-strong candidates underperform.
1. Clarify requirements — functional and non-functional
Don’t start drawing boxes yet. Spend the first few minutes pinning down:
- Functional requirements: what does the system actually need to do? (e.g., for a URL shortener: create a short URL, redirect a short URL to the original, optionally track click counts.)
- Non-functional requirements: how many users, how much traffic, what’s the read/write ratio, what latency is acceptable, does it need to be globally distributed, what’s the consistency requirement?
Interviewers deliberately leave these vague at first — asking good clarifying questions is itself a signal they’re scoring.
2. Capacity estimation (back-of-envelope math)
Turn the requirements into rough numbers: requests per second, storage growth per year, bandwidth. You don’t need precision — you need to show you can reason quantitatively about scale, and the numbers you land on directly inform later design decisions (e.g., whether you need sharding at all).
3. High-level design — draw the boxes
Sketch the major components and how data flows between them: client, load balancer, application servers, cache, database, any async workers. Keep it simple at this stage — a clean, correct high-level design beats a complicated one with holes in it.
4. Data model
Define the core entities and how they’re stored. This is where you decide SQL vs NoSQL, what the schema (or document shape) looks like, and what needs to be indexed.
5. Deep dive on 1-2 critical components
Pick the one or two parts of the system that are actually hard, and go deep. For most systems this is the data layer (how do you scale writes? how do you avoid hot partitions?) or a specific algorithm (how do you generate unique IDs without a central bottleneck?). This is where senior candidates separate themselves from junior ones — showing you know which parts of a system are actually hard is as important as solving them.
6. Identify bottlenecks and trade-offs
Every design has a weak point. Naming it yourself, before the interviewer points it out, is one of the strongest signals you can send. Talk through what would break first under 10x load, and what you’d change.
7. Wrap-up — what you’d do with more time
Briefly mention what you’d add or reconsider given more time: monitoring, rate limiting, multi-region failover, cost optimization. You don’t need to design these — naming them shows you’re thinking beyond the immediate ask.
If you want live support working through problems like this in a real interview, that’s what SyntaxCue is built for.
Trade-offs reference
These come up in almost every system design interview, regardless of the specific question. Know the actual mechanics, not just the terms.
Scaling
- Vertical vs horizontal scaling. Vertical (bigger machine) is simpler but hits a hard ceiling and is a single point of failure. Horizontal (more machines) scales further but requires your application to be stateless — or requires sticky sessions/shared state, which adds complexity.
- Load balancing. Round-robin is simple but ignores server load; least-connections and weighted strategies handle uneven load better. Know that load balancers themselves need redundancy (DNS round-robin or a floating IP setup), or you’ve just moved the single point of failure.
- Stateless vs stateful services. Stateless services (no session data held in memory between requests) are what makes horizontal scaling easy — any request can go to any server. If you need state, push it to a shared store (Redis, a database) rather than keeping it in-process.
Reliability
- Redundancy and failover. Running multiple instances of every critical component, with automatic failover when one dies. The trade-off is cost and complexity vs. the risk of an outage.
- Single points of failure. Any component you run exactly one of is a SPOF. Systematically ask “what happens if this dies?” for every box in your diagram.
- Availability math. “Three nines” (99.9%) is about 8.7 hours of downtime per year; “four nines” (99.99%) is about 52 minutes. Each additional nine gets substantially more expensive to achieve — know this order of magnitude so you can reason about whether a requirement is realistic. Also worth knowing: components chained in series multiply their availabilities, so two 99.9% services in a request path give you roughly 99.8% end-to-end — a reason redundancy matters more as systems grow more components.
Data
- SQL vs NoSQL. SQL gives you strong consistency, transactions, and flexible querying, at the cost of harder horizontal scaling. NoSQL (key-value, document, wide-column) scales writes more easily and often trades away strict consistency or join capability. The real question isn’t “which is better” — it’s which trade-off fits your read/write pattern and consistency requirements.
- Sharding. Split data across multiple databases when a single instance can’t handle the write load or data volume. The hard part is choosing a shard key that avoids hot spots (e.g., sharding by user ID is usually safer than sharding by a value that clusters, like signup date).
- Replication. Leader-follower replication (one write node, multiple read replicas) is simpler and handles read-heavy workloads well. Multi-leader replication allows writes in multiple places but introduces conflict resolution — know that this trade-off exists even if you don’t design a full conflict-resolution scheme in the interview.
- Consistency models. Strong consistency guarantees every read sees the latest write, at the cost of latency and availability during partitions. Eventual consistency allows temporary staleness in exchange for higher availability and lower latency. Naming which one your design needs — and why — is often more important than the specific mechanism.
Caching
- Cache-aside vs write-through. Cache-aside (lazy loading): the application checks the cache first, and on a miss, loads from the database and populates the cache. Write-through: every write goes to the cache and the database together, keeping the cache always current at the cost of extra write latency.
- Eviction policies. LRU (least recently used) is the default choice for most workloads; know that it exists and why you’d pick it over simpler FIFO eviction.
- Cache invalidation. Famously “one of the two hard problems in computer science.” Talk through how stale cached data gets removed or updated — TTLs are the simple answer, explicit invalidation on write is the more correct but more complex one.
- CDN vs application-level caching. CDNs cache static or slowly-changing content close to users geographically; application-level caching (Redis, Memcached) sits close to your backend for dynamic data that’s still read far more than it’s written.
Queues
- When to introduce async processing. Any operation that doesn’t need to complete before you respond to the user (sending an email, processing a video, updating an analytics counter) is a candidate for a queue rather than doing it synchronously in the request path.
- At-least-once vs exactly-once delivery. At-least-once is much easier to implement and is the practical default — it means your consumers need to be idempotent (safe to process the same message twice). Exactly-once is expensive and usually not worth the complexity unless you have a specific reason.
- Backpressure. What happens when producers create work faster than consumers can process it? Naming this and having an answer (bounded queues, load shedding, autoscaling consumers) shows you’re thinking about failure modes, not just the happy path.
Worked example: design a URL shortener
Here’s the full framework applied end-to-end, so you can see how the steps connect rather than just read about them in isolation.
1. Requirements. Functional: given a long URL, generate a short one; given a short URL, redirect to the original. Non-functional: reads vastly outnumber writes (people click links far more often than they create them), low latency on redirect (nobody should notice this in the request path), short URLs shouldn’t collide.
2. Capacity estimation. Say we want to support 100 million new short URLs per month, with a 100:1 read/write ratio. That’s roughly 100M / (30 × 86,400) ≈ 40 writes/second on average, and 4,000 reads/second. Over 5 years, 100M/month × 60 months = 6 billion URLs stored. If each stored record is roughly 500-600 bytes (short code, long URL, metadata), that’s about 3-3.6TB of data over 5 years — large, but very manageable for a sharded key-value store.
3. High-level design. Client → load balancer → stateless application servers → cache (for hot redirects) → database (for the URL mappings) → a background ID-generation service if using a dedicated approach (see step 5).
4. Data model. A simple table/collection: short_code (primary key),
long_url, created_at, optional click_count. This is a natural fit for
a key-value store, since the only real access pattern is “look up by
short_code.”
5. Deep dive: generating unique short codes. This is the interesting part of this problem. Options:
- Hash the long URL (e.g., MD5 or base62-encode part of the hash) and truncate to 6-7 characters. Simple, but collisions are possible and need a retry/check strategy.
- Auto-incrementing counter, base62-encoded. Guarantees uniqueness with no collision handling, but requires a centralized counter, which becomes a bottleneck and a single point of failure at scale. With 7-character base62 codes, you get 62⁷ ≈ 3.5 trillion possible codes — far more than the ~6 billion we’d generate in 5 years.
- Pre-generated key ranges, handed out in batches to each application server (each server reserves, say, 1 million IDs at a time from a coordination service). This avoids a hot central counter on every single request while still guaranteeing global uniqueness — the standard production-grade answer to this specific sub-problem.
6. Bottlenecks. The redirect path (reads) is the hot path — this is what justifies a cache in front of the database, since a small fraction of URLs (recently created or currently viral links) account for a disproportionate share of traffic. Because short-code-to-URL mappings are immutable once created, cache invalidation isn’t a problem here — long TTLs and a high hit rate are easy to achieve. The database write path is comparatively light given the read/write ratio calculated above, so it’s not the first thing to optimize.
7. What we’d add with more time. Analytics on click counts (likely via an async queue rather than incrementing synchronously on every redirect, to keep the hot path fast), custom short codes, expiration/TTL on links, and abuse detection for spam URLs.
Common technical interview questions — and why the “big list” approach is fading
If you search for “common technical interview questions,” you’ll find enormous lists — hundreds of questions to memorize, one page per company. That approach made more sense when interview prep meant guessing which exact question you’d get asked and rehearsing an answer in advance. It’s less useful now for two reasons: real interviewers vary their questions specifically to defeat rote memorization, and — more practically — live, adaptive support during the actual interview (working through whatever question actually comes up, in real time) is a fundamentally different and more durable skill than having memorized answers to a fixed list.
That said, it’s still useful to know the shape of what commonly gets asked. Common categories include:
- Data-intensive systems: URL shorteners, key-value stores, rate limiters — problems where the data layer is the interesting part.
- Real-time systems: chat applications, notification systems, live leaderboards — problems where latency and consistency trade-offs dominate.
- Large-scale content systems: news feeds, video streaming, search autocomplete — problems where read scaling and caching dominate.
- Infrastructure-adjacent systems: distributed locks, job schedulers, web crawlers — problems that test your understanding of coordination and failure handling directly.
The framework above applies to all of them. If you want live support working through problems like these in an actual interview — not a memorized script, but real-time help reasoning through whatever you’re actually asked — that’s what SyntaxCue is built for.
How long should a system design interview answer take?
Most system design interviews run 45-60 minutes total. Budget roughly 5 minutes for requirements and estimation, 15-20 minutes on high-level design and data model, 15-20 minutes on the deep dive, and the remainder for trade-offs and wrap-up. If you're still clarifying requirements after 10 minutes, you're behind.
Do I need to write code in a system design interview?
Usually not full implementations — you're mainly expected to draw diagrams and reason at the architecture level. Some interviewers ask for pseudocode or a specific algorithm (like the ID-generation approach above) as part of a deep dive, but line-by-line implementation isn't the point of this interview format the way it is in a coding interview.
What's the biggest mistake candidates make?
Jumping straight to a detailed design without clarifying requirements or estimating scale first. A technically correct design for the wrong scale (over-engineered for a system that doesn't need it, or under-engineered for one that does) reads as a bigger red flag than an imperfect design that's scoped correctly.
Should I mention specific technologies (like "use Kafka" or "use Redis")?
Yes, but justify the choice rather than name-dropping. "I'd use a message queue here because this can be processed asynchronously, and Kafka specifically because we need ordered delivery within a partition" is much stronger than just saying "Kafka" with no reasoning attached.
How detailed should the data model be?
Detailed enough to show you understand the access patterns (what gets queried, how often, by what key), but you don't need a fully normalized schema with every column typed out. Focus on the entities and relationships that matter for the specific problem.
Is it okay to ask the interviewer questions during the interview?
Yes — asking good clarifying questions early, and checking in periodically ("does this direction make sense before I go deeper?") is a positive signal, not a weakness. Interviewers are often deliberately vague at the start specifically to see whether you'll ask.
Prepping for a live coding round instead? See how SyntaxCue handles a coding interview helper — screenshots of the problem on screen, verbal follow-ups, and code in your own language.