Skip to content
TobussSystems in Practice

System Design Interview Guide: A 5-Step Roadmap

12 min read

System design interviews are not primarily tests of how many technologies you can name. They test whether you can turn unclear requirements into a sensible architecture, explain your decisions and recognise the trade-offs behind them.

This guide organises the preparation into five steps:

flowchart LR
    A["1. Fundamentals"] --> B["2. Scalability"]
    B --> C["3. Architecture patterns"]
    C --> D["4. Data management"]
    D --> E["5. Hands-on practice"]

The goal is not to memorise one perfect architecture. It is to build a repeatable way of thinking.

Step 1: Fundamentals

Before discussing distributed databases or event-driven systems, you need a strong understanding of how requests, APIs, storage and caching work.

Networking

HTTP/1.1 versus HTTP/2

HTTP/1.1 normally processes one outstanding request at a time per connection unless pipelining is used. Browsers often open several connections to compensate, but this adds overhead.

HTTP/2 uses binary framing and multiplexes many request and response streams over a single TCP connection. This makes it more efficient when a page or application needs many small resources.

TCP and connection setup

The TCP handshake uses three messages:

Client → SYN
Server → SYN-ACK
Client → ACK

This adds a network round trip before application data moves. At global scale, connection establishment becomes a meaningful part of latency. QUIC and HTTP/3 reduce some of this cost by combining transport security and connection establishment more efficiently.

DNS

DNS translates a domain name into an IP address. Results are cached at several levels:

  • browser;
  • operating system;
  • local or corporate resolver;
  • recursive DNS resolver.

Caching avoids repeating the complete lookup for every request, but it also means DNS changes take time to propagate according to the configured TTL.

Layer 4 versus Layer 7 load balancing

Layer Uses Strength Trade-off
L4 IP addresses, ports and transport information Fast and protocol-agnostic Cannot route using HTTP content
L7 Hostnames, paths, headers and cookies Intelligent application routing More processing and configuration

An L7 load balancer can route /images and /api to different services, while an L4 load balancer forwards connections without understanding HTTP semantics.

API design

REST versus GraphQL

REST GraphQL
Models resources through endpoints Models data through a query schema
Simple HTTP caching More complicated caching
Can over-fetch or under-fetch Clients request specific fields
Straightforward operational model Flexible for clients with different data needs
Many endpoints may be required One endpoint may serve many query shapes

GraphQL flexibility also creates additional concerns around query cost, authorisation and abuse prevention.

Rate limiting

Rate limiting protects a service from overload and prevents one client from consuming all available capacity.

Token bucket accumulates tokens at a steady rate. A request consumes a token, allowing short bursts while enforcing a long-term average.

Sliding window counts requests within a continuously moving time interval. It provides smoother enforcement but typically requires more state.

Sessions versus JWTs

Server-side session JWT
State is stored by the server Claims are carried in the token
Easy to revoke centrally Difficult to revoke before expiry
Requires shared session storage when scaling Easy for multiple service instances to verify
Session ID is normally stored in a cookie Token must be protected from theft and misuse

JWT revocation is difficult precisely because a service can validate the token without consulting central state. Common mitigations include short expiries, refresh-token rotation and revocation lists.

Database basics

SQL versus NoSQL

Relational databases provide schemas, joins, constraints and transactions. NoSQL systems often provide flexible models and easier horizontal distribution for specific access patterns, but usually trade away some relational capabilities.

Neither category is automatically more scalable. The right choice depends on queries, consistency requirements, data shape and operating scale.

B-tree versus hash indexes

B-tree index Hash index
Maintains sorted keys Maps keys through a hash function
Supports exact matches Excellent for exact matches
Supports range and ordered queries Does not naturally support range scans
Useful for dates and sortable values Useful for equality-based lookups

Range versus hash partitioning

Range partitioning groups nearby key values together. It supports efficient range queries but may create hot partitions when activity concentrates in one range.

Hash partitioning spreads keys more evenly, improving load distribution while reducing range-query locality.

Caching

Pattern How it works Main trade-off
Cache-aside Application reads the cache and loads from the database on a miss Simple, but cached data can become stale
Write-through Writes update the cache and durable store together Consistent reads, slower writes
Write-behind Writes enter the cache and reach storage asynchronously Fast writes, risk during failures

A cache stampede occurs when a popular entry expires and many requests simultaneously query the database. Mitigations include:

  • per-key locks;
  • request coalescing;
  • randomised or staggered expiry;
  • refreshing popular values before expiry;
  • serving stale values briefly while refreshing.

A CDN caches content near users at edge locations. It is particularly effective for static files, images and video. An application or origin cache normally sits closer to the service and can cache dynamic or computed results.

Step 2: Scalability and Performance

Vertical versus horizontal scaling

Vertical scaling Horizontal scaling
Add CPU, memory or storage to one machine Add more machines
Operationally simple Scales beyond one machine’s limit
Eventually reaches a hardware ceiling Requires load distribution and coordination
Can remain a single point of failure Introduces distributed-system failures

Horizontal scaling is not free. Function calls become network calls, replicas can disagree and failures may be partial rather than complete.

Load-balancing algorithms

Round robin cycles evenly through servers. It is simple, but assumes requests and servers have similar cost and performance.

Least connections sends a request to the server with the fewest active connections. It adapts better to unequal request duration, although connection count is not always a perfect measure of actual load.

Consistent hashing places servers and keys on a hash ring. Adding or removing a server moves only part of the keyspace. This is useful for distributed caches because it preserves cache locality during membership changes.

Replication

Leader-follower

Writes go to one leader and are copied to followers. Followers can serve reads, but replication lag means a user may not immediately observe a completed write when reading from a follower.

Multi-leader

Several nodes accept writes. This is useful across regions or disconnected environments, but simultaneous changes can conflict and require a resolution policy.

Quorums

For N replicas, a write may require acknowledgements from W replicas and a read may consult R replicas. Increasing the quorum improves consistency confidence but adds latency and can reduce availability during failures.

Sharding

Strategy Advantage Risk
Range sharding Efficient range queries Hot ranges and uneven growth
Hash sharding Even distribution Poor range-query locality
Directory-based sharding Flexible placement Extra lookup and directory dependency

Resharding is the operational challenge of redistributing data when shards are added, removed or become unbalanced. Consistent hashing and virtual nodes reduce movement, but migration, dual writes and cutover still require careful design.

Asynchronous processing

Kafka versus RabbitMQ

Kafka RabbitMQ
Distributed append-only log Traditional message broker
High-throughput streaming Flexible message routing
Consumers track positions and can replay Per-message acknowledgement and queues
Strong fit for event streams and analytics Strong fit for work queues and routing patterns

This is not an absolute rule. The choice depends on retention, replay, ordering, routing and operating model.

Delivery guarantees

At-least-once delivery means a message should not be lost, but it may be processed more than once. Consumers must therefore be idempotent or deduplicate using a stable event ID.

Exactly-once delivery is much harder to guarantee end to end because messaging, application logic and database writes cross different boundaries. Practical designs usually combine broker guarantees with transactional writes, idempotency and deduplication.

Backpressure

Backpressure is how a system prevents fast producers from overwhelming slower consumers. Possible responses include:

  • slowing or rejecting producers;
  • limiting concurrency;
  • pausing consumption;
  • buffering within bounded queues;
  • shedding low-priority work;
  • scaling consumers when additional parallelism is available.

Without backpressure, queues grow without limit, latency rises and the system eventually exhausts resources.

Step 3: Architecture Patterns

Monolith versus microservices

Monolith Microservices
One deployable unit Independently deployable services
Easier local development and testing Independent ownership and scaling
Simple transactions and calls Network boundaries and distributed data
Deployment coupling increases with size Operational complexity increases with service count

The real trade-off is often deployment coupling versus operational complexity. A well-designed monolith can scale effectively, while poorly bounded microservices can make every change harder.

Event-driven versus request-response

Request-response is synchronous. The caller waits for the result, which is easy to understand but couples its latency and availability to the downstream service.

Event-driven interaction is asynchronous. Producers publish facts and consumers react later. This decouples services in time, but introduces eventual consistency and more complicated failure diagnosis.

Eventual consistency is acceptable when the business can tolerate temporary staleness, such as a delayed social-media counter. It may be unacceptable when checking a bank balance immediately before a withdrawal.

CQRS and event sourcing

CQRS separates the command model used for validating and persisting changes from the query model used for reads. It is valuable when reads and writes differ substantially in shape or scale.

Event sourcing stores state changes as immutable events instead of overwriting the current record. Current state is reconstructed by replaying events.

Benefits include auditability, historical reconstruction and replay. Costs include event evolution, storage, debugging complexity and projection management.

Snapshots periodically store derived state so a service does not need to replay the complete history on every recovery.

Fault tolerance

Circuit breaker

A circuit breaker stops repeatedly calling an unhealthy dependency. It fails fast while the circuit is open and periodically probes whether the dependency has recovered.

Retries with backoff and jitter

Backoff increases the delay between attempts. Jitter adds randomness so many clients do not retry at exactly the same moment and overwhelm a recovering service.

Retries should be used only for transient and safe-to-repeat operations. Retrying an invalid request or a non-idempotent operation can make the problem worse.

Bulkheads

Bulkheads isolate resources such as thread pools, queues and connection pools per dependency. A failure in one integration then cannot consume every resource needed by the rest of the application.

Step 4: Data Management

CAP theorem

During a network partition, a distributed system must choose between:

  • Consistency: every read observes the required latest state;
  • Availability: every request receives a non-error response, even when that response may be stale.

Partition tolerance is not normally optional in a distributed system. CAP is therefore about behaviour during a partition, not about permanently labelling an entire product as only “CP” or “AP”. Different operations may choose different trade-offs.

PACELC

PACELC extends the discussion:

If there is a Partition: choose Availability or Consistency.
Else: choose Latency or Consistency.

Even during healthy operation, synchronously coordinating replicas improves consistency at the cost of latency.

Consistency models

Model Guarantee
Strong consistency Reads observe the latest successful write according to the system’s contract
Eventual consistency Replicas converge, but a read may temporarily be stale
Causal consistency Causally related operations are observed in order
Read-your-writes A client observes its own completed writes

Choose the model from the business invariant. A product catalogue and a payment balance do not necessarily need the same guarantee.

Choosing a storage system

A relational database with suitable indexes can handle substantial scale while preserving joins, constraints and transactions. Most systems should not abandon relational modelling merely because NoSQL sounds more scalable.

NoSQL becomes compelling when the workload has characteristics such as:

  • extremely high write throughput;
  • flexible or rapidly changing document structures;
  • access patterns that do not benefit from joins;
  • very wide time-series data;
  • simple key-based access distributed across many partitions.

The decision should begin with queries and invariants, not a technology label.

Query optimisation

An EXPLAIN plan shows how the database intends to execute a query, including scans, index access, join order and row estimates. It should be the first tool used when investigating a slow query.

A covering index contains every column required by a query, allowing the database to answer from the index without reading the full table row.

The N+1 query problem occurs when an application fetches a list and then runs one additional query for every item. It can often be fixed with a join, batch fetch or one IN (...) query.

Step 5: Hands-On Practice

Design systems end to end

Do not stop at a whiteboard diagram. Define enough detail to expose hidden assumptions:

  • functional and non-functional requirements;
  • traffic and storage estimates;
  • API request and response shapes;
  • status codes and error contracts;
  • database schema and indexes;
  • partition keys;
  • pagination;
  • concurrency behaviour;
  • consistency boundaries;
  • failure and recovery paths;
  • monitoring and capacity signals.

This is where vague designs become testable designs.

Document trade-offs explicitly

For each major decision, state:

We chose X because we are optimising for Y.
The cost is Z.
We would reconsider this decision if condition A changed.

Interviewers are usually more interested in whether you understand the consequences than whether you chose their favourite database.

Practise out loud

Speaking through a design under time pressure is different from silently writing one. Practise with a peer, mentor or recording. Train yourself to:

  1. clarify the problem;
  2. state assumptions;
  3. estimate scale;
  4. draw the high-level architecture;
  5. deepen the critical path;
  6. identify bottlenecks and failures;
  7. explain alternatives and trade-offs.

Debrief each mock interview

After every mock, identify the most important question you should have asked earlier. Common omissions include:

  • expected traffic;
  • read-to-write ratio;
  • latency target;
  • data-retention period;
  • regional distribution;
  • consistency requirement;
  • largest expected object;
  • acceptable data loss;
  • recovery-time objective.

Designing for the wrong constraints is one of the most common system-design mistakes.

A Repeatable Interview Framework

Use this sequence during the interview:

1. Clarify requirements

Separate must-have functionality from optional scope. Ask about users, scale, latency, consistency, security and availability.

2. Estimate scale

Calculate rough requests per second, storage growth, bandwidth and read/write ratios. Approximate numbers are enough if the assumptions are explicit.

3. Define APIs and data

Identify core entities, API operations, schemas, indexes and partition keys.

4. Draw the high-level flow

Show clients, gateways, services, storage, caches and asynchronous components. Keep the first diagram simple.

5. Deep-dive into the hardest path

Choose the most important risk: fan-out, ordering, consistency, hot keys, search, delivery guarantees or multi-region failover.

6. Cover failures and operations

Explain retries, timeouts, idempotency, replication, monitoring, recovery and deployment.

7. Summarise the trade-offs

End by stating what the design optimises for, what it sacrifices and what would change at ten times the scale.

Systems Worth Designing

Practise these systems end to end:

  • URL shortener;
  • distributed rate limiter;
  • news feed or timeline;
  • chat application;
  • distributed cache;
  • file-storage or Dropbox-like platform;
  • ride-sharing dispatch;
  • notification system.

For each exercise, avoid copying a standard diagram. Change one important constraint and observe how the design changes. For example:

  • require global active-active writes;
  • require strict ordering per user;
  • allow no data loss;
  • support very large files;
  • add a 100 ms latency target;
  • require data residency by country.
  1. Shrayansh Jain
  2. Rajat Gajbhiye
  3. Gaurav Sen
  4. Arpit Bhayani

Final Advice

A strong system design answer is not the biggest possible architecture. It is an architecture that matches the stated requirements and whose weaknesses you understand.

Start simple. Make assumptions explicit. Deepen the parts that carry the most risk. Explain what fails, how the system recovers and why each major trade-off is acceptable.

That is the skill the interview is really testing.