Ga naar hoofdinhoud

System Design Interview Questions (Beginner to Advanced)

Work through 41 questions by level and role, study each worked answer and its likely follow-up, then practice production scenarios.
Josep Ferrer
Josep Ferrer

Maak je gratis account aan

Oefen en volg je voortgang.

Ga verder met GoogleDoor verder te gaan, accepteer je ons Gebruiksvoorwaarden, onze Privacybeleid en dat je gegevens in de VS worden opgeslagen.

System design questions show up in more interviews than you'd expect. Backend roles, obviously. But also infrastructure, data engineering, and even product-heavy positions where nobody expects you to write a line of code during the loop.

So what is the interviewer actually testing? Not whether you know the "correct" architecture, because there isn't one. They want to see structured thinking, honest tradeoffs, and whether you can keep reasoning when the constraints are fuzzy and the clock is running.

Expectations shift a lot by level. A junior candidate who asks good clarifying questions and sketches a clean diagram with a handful of boxes is doing great. A senior candidate who does only that is in trouble, because at that level people expect numbers, failure modes, and an opinion about what to build first.

Role matters too. A data engineer gets pushed on pipelines and backfills, a frontend developer on caching and state, an infra person on rollouts and blast radius. Same underlying skill, different vocabulary.

I bring this up because most question lists ignore both dimensions and just dump 50 prompts on you. This one is organized by level first, then by role, with scenario questions at the end. If the storage side of these answers feels shaky, our Database Design course covers the fundamentals.

How to Approach a System Design Interview

Same structure every time, roughly 45 minutes:

  1. Clarify (5 min). Who uses it, what must it do, what's out of scope, and what "good" looks like.
  2. Put numbers on it (2 min). Users, requests per second, read/write mix, storage growth per year. Rough is fine, silent is not.
  3. Sketch the high level (10 min). Clients, API layer, storage, cache, queue. Five or six boxes, no more.
  4. Show the data model (5 min). Tables or collections, keys, and the access patterns they serve.
  5. Deep dive on one piece (10 min). Let the interviewer pick, or offer the part you find most interesting.
  6. Failure modes and tradeoffs (rest). What breaks, what you'd monitor, what you'd build first if this were real.

Narrate the whole thing out loud. An interviewer can't score silent thinking.

Beginner System Design Interview Questions

These test fundamentals: clarifying requirements before drawing anything, producing a simple architecture diagram, and making sensible storage choices. Nobody expects consensus algorithms here.

1. Design a URL shortener

A shortener turns a long URL into a short code and redirects on visit, so the first things to settle are whether links expire and how many you expect. A reasonable assumption is 100 million new links a month, with reads about 100x writes.

That read-heavy mix shapes the design: an API server, a database, and a cache in front of it. For the short code, either base62-encode an auto-incrementing ID (seven characters gives about 3.5 trillion combinations) or generate a random string and check for collisions.

A single table does the job: short_code as the primary key, long_url, created_at, expires_at, and an optional user_id. Hot codes live in Redis so the database only sees misses. Use a 302 redirect if you want click analytics, because browsers cache a 301 and you never see the second visit.

High-level design for a URL shortener

At 10 billion links you shard by code and the ID generator becomes the bottleneck, and if people start guessing codes you switch from sequential to random and add rate limiting.

2. Design a basic rate limiter

A rate limiter allows N requests per user per minute and returns a 429 beyond that. The first thing to clarify is whether the limit is per user, per IP, or per API key, because that decides your cache key.

Three algorithms cover most answers. Fixed window counts requests in each minute bucket, which is simple but allows double the limit at the boundary. Sliding window log stores every timestamp, which is exact but memory-hungry. Token bucket refills at a steady rate and lets small bursts through, which is why many gateways use it.

Run the limiter as middleware in the API gateway with counters in Redis under a TTL; INCR plus EXPIRE covers the fixed-window version.

With ten gateway instances you either share the Redis counters or accept slight over-counting with local ones, and you should decide up front what happens if Redis dies: fail open and risk abuse, or fail closed and block everyone.

3. Design a simple key-value store

A key-value store needs get, put, and delete, and for a beginner question, you should keep it to a single node. An in-memory hash map handles the operations. For durability, append every write to a log on disk before acknowledging it, and take periodic snapshots so recovery doesn’t replay the whole history.

What the interviewer wants to hear is that you’ve separated the fast path in memory from the durable path on disk, and that you understand why the log comes first.

If the data outgrows memory, the answer is an LSM tree, which is roughly how RocksDB and Cassandra work. If you need a second node, the primary replicates the log to a follower, and consistent hashing takes over once you go beyond that.

4. Design a cache (conceptual)

A cache sits between your application and a slower store, and the basic pattern is cache-aside. The app checks the cache, misses, reads the database, writes the result back with a TTL. Simple, but you own the invalidation logic.

Eviction usually means LRU, sometimes LFU for skewed workloads. The metric that matters is hit ratio; below 80% or so you should ask whether the cache is helping at all.

Where things get interesting: staleness. If the database changes and the cached copy doesn't, users see old data until the TTL expires. Short TTLs reduce that window but raise database load.

When a popular key expires and 10,000 requests hit the database at once, you either coalesce those requests or refresh the key before it expires. On write-through versus write-back, write-through keeps the cache correct at the cost of slower writes, while write-back is fast but loses recent writes if the cache dies before flushing.

5. Design a basic notification service

A notification service sends email, SMS, and push messages and retries when a provider fails. Before designing it, ask about volume and whether delivery order matters, which it usually doesn’t.

The core of the design is a queue. Producers write a notification event to it, and a worker per channel pulls events and calls a provider like SendGrid or Twilio. That split keeps the thing deciding to notify separate from the thing actually sending, so a slow SMS provider never blocks the app.

Store each notification with a status (pending, sent, failed) and an idempotency key so a retried event doesn’t send twice.

Users who want marketing off but security alerts on need a preferences table checked before anything is enqueued, and a provider that caps you at 100 messages per second needs per-channel throttling in the worker.

6. Design a simple file storage service

Think Dropbox at tiny scale. Users upload a file, get a link, download it later. Clarify max file size and whether sharing matters.

Metadata (owner, filename, size, checksum, created date) goes in a relational database. The bytes go in object storage such as S3, never in the database. For uploads, the API returns a pre-signed URL so the client writes directly to object storage and your servers never touch the file.

Two users uploading the same 2 GB file is a dedupe problem solved by hashing the content, and files over 5 GB need multipart upload with a checksum per chunk.

7. Design a game leaderboard

A leaderboard has to update a player’s score, return the top 10, and return one player’s rank, and the first things to ask are how many players there are and how often scores change.

A relational table with an index on score works up to a point, but "what's my rank" becomes a COUNT over everyone above you. Redis sorted sets solve this: ZADD to update, ZREVRANGE for the top N, ZREVRANK for a single player, all in logarithmic time.

Daily and all-time boards are one sorted set per period, keyed like lb:2026-09-14. If 50 million players push Redis memory too far, keep only the top 100k there and the rest in the database.

Intermediate System Design Interview Questions

At this level the interviewer assumes you've built and operated real systems. The questions introduce queues, read/write scaling, and the tension between latency, cost, and consistency.

8. Design a news feed

A feed needs users to post, follow others, and read what the people they follow have written, in reverse-chronological or ranked order. Assume 10 million daily active users opening it five times a day, which works out to roughly 600 reads per second on average and far more at peak.

The central choice is when to assemble the feed. Fan-out on write pushes each new post into every follower’s precomputed feed, giving fast reads at the cost of expensive writes. Fan-out on read assembles it at request time, which flips that tradeoff. Most real systems mix them, fanning out on write for normal users and on read for accounts with millions of followers.

The data model is posts, follows, and a per-user feed list in Redis holding post IDs. Paginate with a cursor on post ID rather than an offset.

Fan-out on write versus fan-out on read

Adding ranking later doesn’t mean rebuilding any of this; you score the candidate IDs from the feed list at read time.

9. Design a chat system with multi-device sync

Chat with multi-device sync means one-to-one and group messages, delivery to every device a user owns, and history that survives a phone change. Assume 50 million daily users sending about 40 messages each, which is 2 billion a day, or roughly 23,000 writes per second on average and several times that at regional peaks.

Each client holds a WebSocket to a chat server, which writes messages to a store partitioned by conversation ID with an increasing sequence number per conversation. Every device remembers the last sequence number it saw and asks for anything newer on reconnect, which is what makes multi-device sync work.

The store needs high write throughput and range reads by conversation, so wide-column databases like Cassandra are the usual answer. Delivery and read receipts are small events flowing back along the same path.

When two friends are connected to different chat servers, either pub/sub between the servers or a routing service that maps users to servers gets the message across. Groups of 500 fan out on the server side, and ordering guarantees get harder to keep.

10. Design a ride-sharing matching service

Keep this lighter than the senior version. Drivers send their location every few seconds, riders request a trip, and the service has to return a nearby driver within a couple of seconds.

Location updates are the volume problem: 200,000 active drivers at one update every 4 seconds means 50,000 writes per second. Store current locations in memory indexed by geohash or H3 cell, not in a relational table. Matching then means "find drivers in my cell and the neighboring ones," rank by ETA, and lock one driver so two riders don't get the same car.

If a driver accepts and then loses connectivity, the lock times out and the rider is re-matched. A hot cell in a city center gets finer cells in dense areas, which is exactly what hierarchical indexes like H3 give you.

11. Design a metrics collection system

A metrics system takes a few hundred metrics every 10 seconds from thousands of servers and lets engineers query them in dashboards.

Agents batch metrics and push to an ingestion layer, which writes to a time-series database (or a Kafka topic with consumers writing to one). Storage is tiered: raw resolution for a day or two, one-minute rollups for a month, hourly for a year. Downsampling runs as a background job.

Queries hit the rollup that matches the time range requested, which keeps a 30-day chart from scanning raw data. Tag cardinality (user IDs as a label, for instance) will kill the database, so say that out loud.

On push versus pull, Prometheus pulls, but push works better through firewalls and for short-lived jobs. An agent reporting out-of-order timestamps gets accepted inside a bounded lateness window and rejected beyond it, with a counter on rejections so a broken clock shows up.

12. Design a search autocomplete system

Autocomplete returns the top five completions within about 100 milliseconds of each keystroke. Clarify whether suggestions are global or personalized, because personalization changes everything.

he answer is to precompute. An offline pipeline aggregates query logs, counts frequencies, and builds a trie (or a prefix-to-top-k table) where every node already stores its best completions. The serving layer then does a single lookup per keystroke, and the whole structure fits in memory across a few replicas.

Updates happen in batch, maybe hourly, by rebuilding the structure and swapping it in. Trending queries can get a small real-time overlay merged at request time.

A prefix like “a” would hit a huge subtree, which is why you store top-k at each node rather than traversing. Typos need a separate fuzzy index, or you accept the miss.

13. Design a distributed job scheduler

A distributed job scheduler is cron for a whole company: define a job and a schedule, run it at the right time and at most once per tick, retry on failure, and show what happened.

Store job definitions and schedules in a database. A scheduler service computes the next run time for each job and pushes due jobs onto a queue; worker pools pull and execute. The tricky bit is running exactly one scheduler instance per job without a single point of failure, which usually means leader election (a lock in ZooKeeper, etcd, or a database row with a lease).

Record every execution with status, start time, end time, and logs location. That table becomes the thing people actually look at.

A job that runs longer than its interval should skip, queue, or overlap, and that should be configurable. Once job B depends on job A, dependencies become a DAG, and the scheduler only enqueues when upstream has succeeded.

Advanced System Design Interview Questions

Senior-level territory. Huge scale, multi-region, reliability targets you can state as numbers, and the cost of every decision. The interviewer expects you to volunteer failure modes before being asked.

14. Design a video streaming platform like YouTube

Video streaming is two systems under one name. On upload, a user pushes a raw file and a pipeline transcodes it into several resolutions and bitrates, chunks it into a few seconds each, and stores the chunks in object storage. On playback, a CDN serves those chunks and the player switches bitrate to match the user’s bandwidth, which is adaptive streaming via HLS or DASH.

State the scale: hundreds of hours uploaded per minute, billions of views a day, storage in the exabytes. Transcoding is embarrassingly parallel, so a large worker fleet pulls jobs from a queue. Metadata such as title, owner, and view count lives in a sharded database with heavy caching because the home page reads it constantly. Object storage and CDN edges replicate across regions, and the SLO that matters is playback start time, with rebuffering ratio as the metric users feel.

View counts on a viral video are approximate counters aggregated in batches, never a database increment per view, and copyright matching is a fingerprinting job in the same upload pipeline.

15. Design a distributed logging platform

A logging platform takes logs from every service, makes them searchable within seconds, and keeps them 30 days hot and a year cold.

Agents tail log files and ship them to a durable buffer like Kafka, which absorbs spikes and lets indexers fall behind without losing data. Indexers write to a search cluster with one index per day per service, and old indices roll down to compressed files in object storage.

Cost is the real constraint, so index structured fields and keep raw text cheap. Give each service a quota, monitor index lag, and scrub PII at ingestion.

A service logging at 100x its normal volume gets quota’d, sampled, dropped, and alerted on, in that order. Cross-region queries mean federated search, with each region owning its own data.

16. Design a real-time analytics system

Real-time analytics means dashboards showing aggregates over the last few minutes, updated within seconds, on top of a stream of perhaps a million events per second.

A stream processor such as Flink maintains windowed aggregates, say per-minute counts by dimension, and writes them to a fast-read store like ClickHouse or Druid. Dashboards query that store, never the raw stream.

Name the tradeoffs: exact counts versus HyperLogLog for distinct users, tumbling versus sliding windows, and watermarks for late events. Set a freshness SLO and monitor processor lag against it.

A high-cardinality dimension like user ID will explode the aggregate table, so query raw events for that one. Backfilling after a bug means replaying from the stream with retained offsets.

17. Design a payments system

Payments are the one design where correctness beats scale. The system has to charge a customer, record it, never double-charge, never lose a record, and reconcile with the bank daily.

Idempotency carries most of that: every request has a key, and the service stores the result against it and returns the same result on retries. Money moves through an append-only double-entry ledger where each transaction’s entries sum to zero, in a relational database with serializable isolation. This is one place where eventual consistency is the wrong answer.

Card-network calls can time out ambiguously, so charges get a pending status and a reconciliation job settles them. Multi-region means a home region per account, never active-active writes on the same balance.

Multi-currency means integer amounts in minor units with a currency code, and a refund arriving before its charge settles is handled by a state machine with explicit transitions.

18. Design a large-scale messaging system

A large-scale messaging system lets producers publish and consumers subscribe, survives broker restarts, and preserves order where it matters, at millions of messages per second.

Partition each topic so messages with the same key land on the same partition, which gives ordering per key without global ordering. Each partition is an append-only log replicated to a few brokers, and consumers commit their offset after processing.

Default to at-least-once delivery with idempotent consumers. Retries go through a retry topic with backoff and poison messages to a dead-letter queue. Consumer lag is the signal to set an SLO on, and across regions, one region owns writes per key or the two will reorder each other.

A consumer that crashes after processing but before committing produces a duplicate, which is why idempotency matters. Rebalancing storms are tamed with sticky assignment and cooperative rebalancing.

Backend Engineer System Design Interview Questions

These focus on APIs, data models, and where service boundaries go. Expect follow-ups about consistency, caching, and what you'd log.

19. Design an authentication and authorization service

Authentication answers “who are you” and authorization answers “what can you do,” and interviewers like candidates who keep those separate.

Use OAuth 2.0 and OpenID Connect rather than inventing a protocol. Issue short-lived access tokens and longer-lived refresh tokens stored server-side so you can revoke them. Permissions live in a roles model checked by a small library or a policy service. Log every login attempt, refresh, and denial with IP and device, and never log the tokens themselves.

JWTs avoid a lookup per request, but revoking one early means a denylist, which puts the lookup right back. Credential stuffing is slowed by rate limiting per IP and per account, delays after repeated failures, and a second factor on suspicious logins.

20. Design an API gateway

An API gateway is a single entry point in front of your services that handles the cross-cutting work so each service doesn’t: routing by path and version, TLS termination, authentication, rate limiting, and request logging.

The gateway itself should be stateless and horizontally scaled behind a load balancer. Route configuration lives in a control plane and gets pushed to gateway instances, so you never redeploy the gateway to add a route. Auth tokens get validated once at the edge and the gateway forwards the user identity as a header.

Blast radius is the thing to say out loud. The gateway is on every request path, so a bad config push takes everything down; validate configs, roll them out gradually, and keep the gateway's own logic thin.

Versioning without breaking mobile clients you can’t update means path or header versioning with old versions kept alive. And the gateway shouldn’t aggregate responses from several services; that belongs in a backend-for-frontend layer.

21. Design an orders system for an e-commerce site

An orders system creates an order, reserves inventory, takes payment, ships, and lets the customer see status. Orders are a state machine (created, paid, packed, shipped, delivered, cancelled), and the allowed transitions should be explicit.

Order creation is a POST with an idempotency key so a double-click doesn't produce two orders. Inventory reservation and payment involve other services, so use a saga: each step publishes an event, and failures trigger compensating actions (release inventory, refund). Write the event to an outbox table in the same transaction as the order update so the database and the message bus never disagree.

On the read side, an orders table plus an order_items table, with a materialized order summary cached for the "my orders" page.

Two customers buying the last unit at once is resolved by a row lock or atomic decrement on inventory, with one of them getting an out-of-stock message. The thing to monitor is orders stuck in a state longer than expected.

22. Design a feature flag service

A feature flag service toggles features per environment, targets by user attributes or percentage, and flips a flag globally within seconds when something breaks.

Flag definitions and targeting rules live in a small database behind an admin API. Applications embed an SDK that fetches all flags on startup, caches them locally, and evaluates rules in-process, so a flag check costs nothing at request time. Updates propagate through a streaming connection or short polling, and the SDK keeps the last known state if the flag service is down.

Evaluate percentage rollouts with a stable hash of user ID and flag key, so the same user always lands on the same side.

Stale flags are found by tracking last-evaluated timestamps and nagging owners, and if the flag service is down at startup the application falls back to defaults shipped in code.

23. Design a recommendation serving API

A recommendation API returns 20 items for a user in under 100 milliseconds at a few thousand requests per second, and no deep ML is needed to design it.

Split offline and online. An offline job computes candidate lists per user into a low-latency key-value store. The online API fetches those, reranks with a few fresh features like in-stock status, filters out what the user already bought, and returns the list. Keep a fallback of popular items by category, and log every served list with a request ID so you can join it to clicks later.

A new user gets the fallback until a few interactions come in. The 100 milliseconds split roughly into 10 for the fetch, 30 for rerank, 10 for serialization, and 50 of headroom.

Infrastructure / DevOps System Design Interview Questions

Reliability, deployment, automation, and observability. The recurring theme: how do you change things safely and know quickly when you were wrong.

24. Design a CI/CD pipeline for microservices

A CI/CD pipeline for microservices has to handle dozens of independently deployable services with tests, security checks, and a path to production that doesn’t require a human at 3 a.m.

Build once, deploy the same artifact everywhere. The pipeline lints, runs unit tests, builds a container image tagged with the commit SHA, scans it, and pushes it to a registry. Deployment then promotes that image through environments (dev, staging, production) using configuration rather than rebuilding.

Production rollout should be progressive: canary to a few percent of traffic, watch error rate and latency for a defined window, then continue or roll back automatically. Rollback means redeploying the previous image tag, which is fast precisely because you never rebuilt.

When service A’s change breaks service B’s contract, the fix is contract tests in CI and backward-compatible API changes. Monorepo versus many repos matters less than people think, as long as the pipeline only builds what changed.

25. Design centralized monitoring and alerting

Centralized monitoring brings metrics, logs, and traces from every service into one place, with alerts that wake people up only when users are affected.

Metrics flow to a time-series store, logs to the platform from question 15, traces to a tracing backend, all correlated by a shared request ID. The design decision that matters is what you alert on. Alert on symptoms (error rate, latency percentiles, saturation) tied to SLOs, not on causes like "CPU at 80%."

Paging fatigue kills on-call rotations, so every page needs a runbook and a review. Anything that pages twice in a week without a clear action gets demoted to a ticket.

An SLO for a brand-new service comes from measuring for a couple of weeks and then setting a target slightly better than current. And when the monitoring system itself is down, external synthetic checks and a dead-man’s switch alert are what tell you.

26. Design a secrets management approach

Secrets management makes database passwords, API keys, and certificates available to services at runtime, never in source control, rotated regularly, and audited.

A central secrets store (HashiCorp Vault, a cloud provider's secrets manager) holds everything. Services authenticate to it using their workload identity (a Kubernetes service account, an IAM role), never a long-lived token, and fetch secrets at startup or on demand. Prefer dynamic secrets where possible: the store generates a database credential valid for an hour, and rotation happens for free.

Audit every read. And keep a break-glass path documented for when the secrets store itself is down, because it will be.

A key a developer accidentally commits gets caught by scanning in CI, rotated immediately, and treated as compromised regardless. Secrets in environment variables are common but leak through crash dumps and child processes, so mount them as files or fetch them in-process.

27. Design autoscaling and a rollout strategy

Autoscaling and rollout together have to let a service handle daily traffic swings of 5x without manual intervention while deploys go out several times a day.

Scale on a signal that tracks user pain, usually request rate or latency per instance, rather than CPU alone. Set minimum replicas so a cold start never faces a spike, and a maximum so a bug can't bankrupt you. Scale up fast and down slowly.

For rollout, use blue/green when you need an instant switch and instant rollback, and canary when you want to observe real traffic on a small slice first. Combine canary with the autoscaler carefully, because a canary that scales independently can skew your comparison.

If scaling lags a sudden spike by two minutes, predictive scaling on a schedule or a higher minimum covers the gap. And 50 new instances exhausting database connections is why connection pooling belongs in a proxy layer.

Data Engineer System Design Interview Questions

Pipelines, storage formats, batch versus streaming, and whether the data can be trusted. The same framework as before, but the failure modes are about lost, duplicated, or late data rather than lost requests.

28. Design an event ingestion pipeline

An event ingestion pipeline takes behavioral events from web and mobile clients and makes them queryable within an hour. Assume 50,000 events per second at peak, with clients that go offline and retry.

Clients batch events through an SDK and post to a collector service that validates against a schema registry and writes to a stream (Kafka or a managed equivalent). A consumer lands raw events in object storage partitioned by hour, in a columnar format like Parquet. Downstream jobs read from there.

Retries mean duplicates, so every event carries a client-generated UUID and the landing job dedupes within a window. Schema changes go through the registry with compatibility checks, because a mobile app on an old version will keep sending the old shape for months.

Event ingestion pipeline, with the dead-letter path and the real-time branch.

An event with a timestamp from three days ago lands by arrival time, keeps its event time as a column, and lets downstream decide. Bad events go to a dead-letter path and are never dropped silently.

29. Design a streaming ETL system

Streaming ETL transforms events as they arrive, joins them with reference data, and writes results to a serving store within seconds.

A stream processor reads from the ingestion topic, applies transformations, and enriches with reference data loaded in-memory and refreshed periodically. State (for windowed joins or aggregations) checkpoints to durable storage so a crashed job resumes without reprocessing from the beginning.

The tradeoff interviewers want named: exactly-once versus at-least-once. Exactly-once is achievable end to end if the sink supports transactions or idempotent writes, but it costs latency and complexity. At-least-once with idempotent sinks gets you most of the benefit.

Late data gets handled with watermarks and a defined grace period, after which it goes to a late-arrivals table.

Reference data that changes mid-stream should be versioned, with the join on the version valid at event time. A backfill six months after a logic fix replays from raw storage in batch, not through the stream.

30. Design a data warehouse and modeling approach

A warehouse has to give analysts and dashboards consistent metrics across sales, marketing, and product data, with history preserved.

Land raw data untouched in a bronze layer, clean and conform it in silver, and build business-facing tables in gold. Model gold as a star schema: fact tables at the finest useful grain (one row per order line, say) and dimension tables for customers, products, dates. Slowly changing dimensions get Type 2 treatment where history matters, so a customer's region change doesn't rewrite last year's revenue.

Partition large fact tables by date, cluster by the columns people filter on, and keep transformations in version control (dbt or equivalent) with tests.

When two teams define “active customer” differently, a metrics layer with one enforced definition settles it. A late-arriving fact that references a dimension key not yet present gets a placeholder dimension row that’s backfilled later.

31. Design a feature store

A feature store computes features once and reuses them for both model training and online prediction, without training/serving skew, and this one stays high level. It’s two stores with one definition: the offline store (a warehouse or lake) holds feature history for building training sets, and the online store (Redis, DynamoDB) holds the latest value per entity for low-latency lookup at prediction time.

A single feature definition drives both, and a job materializes from offline to online on a schedule.

The critical concept is point-in-time correctness. When you build a training set, each row must use feature values as they existed at that row's timestamp, not the current ones. Otherwise your model learns from the future and looks great until it ships.

A feature that’s expensive to compute in real time is either precomputed with some staleness or computed on write. To know online and offline values match, sample and compare them, and log the features you actually served.

32. Design a data quality and lineage layer

A data quality and lineage layer detects broken data before dashboards do and answers “where did this column come from” without reading code.

Quality checks run as pipeline steps: row counts against expected ranges, null rates, freshness (did the partition land on time), and a few business assertions (revenue is never negative). Failures block downstream jobs and alert the owner. Store check results over time so you can see drift, not just today's pass or fail.

Lineage gets captured from the transformation code itself (SQL parsing, or the orchestration tool's metadata) and stored as a graph: table to table, column to column where possible. That graph powers impact analysis when someone wants to drop a column.

If checks take longer than the pipeline, sample, or run the heavy ones asynchronously and alert rather than block. Lineage across tools that don’t talk to each other means OpenLineage or manual annotations, with the gaps documented.

Frontend / Full-Stack System Design Interview Questions

Client performance, state management, caching, and how the browser talks to the API. Security basics show up here too.

33. Design the architecture for a high-traffic web app

A high-traffic web app here means a content-heavy site with millions of daily visitors, fast first paint, and personalized sections for logged-in users.

Static assets go on a CDN with long cache lifetimes and hashed filenames. Pages that are the same for everyone get server-side rendered and cached at the edge; personalized parts load client-side after the shell paints. That hybrid keeps time-to-first-byte low without serving stale personal data.

API calls from the client go through the gateway with short-lived tokens. Set cache headers deliberately: Cache-Control with stale-while-revalidate for content that can be a few seconds old, no-store for anything personal.

For a dashboard behind login, client-side rendering is usually fine, since SSR buys little without SEO. And a cache key that accidentally includes the session cookie gives everyone their own copy, so the hit rate collapses.

34. Design offline-first sync

Offline-first sync means a note-taking or field-data app that works with no connection and syncs when it’s back, without losing anyone’s edits.

Every write goes to a local store first (IndexedDB, SQLite on mobile) and to a queue of pending mutations. When connectivity returns, the client pushes the queue in order and pulls changes since its last sync token. Each mutation carries a client ID and a sequence number so the server can dedupe.

Conflicts are the whole problem. Last-write-wins is simple and loses data. Field-level merging handles most cases.

CRDTs give automatic merges for text and lists at the cost of complexity, and I'd only reach for them if collaborative editing is a real requirement.

A user who edits on two devices offline and brings both back gets both edits applied, the conflict flagged, and the UI showing it. A pending queue that grows to 10,000 mutations should be compacted, so ten edits to one field become one.

35. Design real-time UI updates

Real-time UI updates mean a dashboard or chat view that reflects server-side changes within a second for thousands of concurrent users.

Choose the transport by direction. Server-Sent Events when data only flows server to client (live scores, notifications); WebSockets when the client sends a lot too (chat, collaborative editing). Long polling as a fallback for networks that block both.

On the server, a pub/sub layer fans out changes to whichever connection server holds the user. On the client, handle reconnection with backoff and resume from the last event ID so a dropped connection doesn't mean a lost update. Throttle rendering: 50 updates a second to a chart should batch into a few repaints, not 50.

100,000 users watching one live event is server-side fan-out, possibly through a CDN that supports streaming. Authenticating a WebSocket means a token in the initial handshake, re-validated periodically.

36. Design a client-side performance plan for dashboards

The goal is an analytics dashboard with 20 charts that loads in under three seconds and stays responsive while filtering.

Don't fetch 20 charts at once. Load the visible ones first, lazy-load the rest on scroll, and show skeletons rather than spinners. Pre-aggregate on the server so the client receives a few hundred rows per chart, never raw events.

Cache query results in memory keyed by filter state, so toggling a filter back and forth doesn't refetch.

Tables with thousands of rows need virtualization (render only what's on screen). Heavy computations go to a web worker so the main thread stays free for interaction.

If the API is slow and you can’t change it, cache aggressively, show stale data with a timestamp, and refresh in the background. CORS errors when the dashboard calls a new API mean the API has to allow the dashboard’s origin, and you should be able to explain preflight requests.

Scenario-Based System Design Interview Questions

These test judgment rather than architecture. Requirements change, production breaks, and the interviewer wants to see how you triage.

37. Traffic spikes 10x overnight. What changes first?

Start with what breaks first, and it's rarely the stateless tier. Autoscaling handles the web servers; the database, the cache, and any third-party rate limits are where things fall over.

Immediately, check the saturation metrics (connections, CPU, queue depth) for the database and cache, raise the autoscaler ceiling, and turn on any load shedding you have, such as dropping non-critical features or serving cached pages. Within a day, add read replicas, tune the cache hit ratio, and find the queries that dominate. Longer term, do the sharding and queueing work you’d been putting off.

Telling real growth from a bot comes down to request patterns, user agents, and whether conversions moved.

38. You're hitting database read limits. Cache, replicas, or sharding?

In that order, usually. A cache in front of the hottest reads is cheap and can cut database load in half within a day; check the hit ratio and the query log to confirm the reads are actually repetitive.

Read replicas come next when the read mix is broad rather than hot. They add replication lag, so any read-after-write path (a user saves and immediately sees their change) needs to go to the primary. Sharding solves write limits more than read limits and costs you cross-shard queries and a migration, so it's last, and only when the first two are exhausted.

If one massive customer on a single table is causing the load, isolate that tenant or partition by customer ID.

39. A critical downstream dependency is flaky. Retries, timeouts, circuit breakers?

All of them, and in the right order. First a timeout, because a call with no timeout turns a slow dependency into your own outage as threads pile up. Then retries with exponential backoff and jitter, but only for idempotent calls and only a couple of times, or you amplify the load on a service that's already struggling.

Then a circuit breaker: after a threshold of failures, stop calling for a while and serve a fallback (cached data, a degraded response, a friendly error). Monitor the breaker state; a breaker stuck open is its own incident.

When the flaky dependency is your payment provider there’s no fallback for the charge itself; queue the order as pending and process it later.

40. Latency regressed after a launch. How do you diagnose?

First, confirm it's real and scoped: which percentile moved (p50 or only p99), which endpoints, which region. Compare against the deploy timeline; if the regression lines up with a release, roll back first and investigate second.

If rollback isn't the answer, follow the request. Traces show which span grew. Common culprits: a new query without an index, an N+1 pattern introduced by a new field, a cache key change that dropped the hit ratio, or a downstream call that used to be async and is now on the request path.

If only p99 moved and rolling back didn’t help, look for garbage collection pauses, a noisy neighbor, or a lock.

41. A data inconsistency bug appears. What do you check, what do you roll back?

Scope the damage before touching anything. Which tables or records disagree, since when, and is it still happening? The "since when" answer usually points to a deploy or a job run.

Check the write path for the affected records: recent migrations, a job that ran twice, a retry without idempotency, a race between two writers. Stop the bleeding by pausing the offending job or rolling back the code, then repair from a source of truth (the raw event log, the ledger, a backup) rather than hand-editing rows. Keep a record of what you changed and why.

With no source of truth to repair from, reconstruct what you can, flag the rest, and add the outbox pattern so it doesn’t happen again.

Common Mistakes in System Design Interviews

Most candidates fail for the same handful of reasons. None of them are about knowing less.

  • Skipping clarifying questions. Jumping straight to boxes means you might solve the wrong problem for 40 minutes.
  • No numbers. "It needs to scale" means nothing. 5,000 writes per second and 2 TB a year means something, and it changes the design.
  • One perfect architecture. Interviewers want to hear "I'd pick X because Y, and the cost is Z." A single confident answer with no tradeoffs reads as memorized.
  • Microservices too early. A monolith with good boundaries is a fine answer for most beginner and intermediate questions. Splitting into 12 services on the whiteboard adds failure modes you now have to defend.
  • Ignoring operations. How does it deploy, what do you monitor, what happens when a node dies. Senior interviewers will ask, and juniors get bonus points for volunteering.
  • Forgetting the data model. Boxes and arrows with no idea what's in the tables. This one is especially costly for data roles.
  • Going quiet. Thinking silently for two minutes feels like an eternity to the interviewer. Narrate, even if it's "I'm weighing two options here."

How to Prepare for System Design Interviews

Preparation works when it's repeatable. Here's a process that I'd actually follow.

  • Use the same structure every time. The six steps from the top of this article, in that order, on every question you practice. Write them on a card and rehearse until the sequence is automatic and you stop burning attention on what comes next.
  • Do timed mock interviews. Grab a friend, a colleague, or just a voice recorder, and run 45 minutes out loud with someone interrupting you with follow-ups. The first few will be rough, and that's the point.
  • Build a design template. A one-page cheat sheet listing the patterns you keep reaching for: cache-aside, queues for decoupling, pub/sub for fan-out, CQRS when reads and writes diverge, sharding by key, outbox for consistency across a database and a bus. Review it before every session.
  • Practice explaining tradeoffs, not just drawing. For each pattern on that sheet, be able to say in one sentence what it buys you and what it costs. That sentence is what separates a pass from a strong pass.
  • Go by level and role. Pick five questions from your level and four from your role in this list, and rehearse those properly rather than skimming all 41. If the data pipeline questions felt unfamiliar, Our Introduction to Data Engineering and Streaming Concepts courses cover the vocabulary those answers depend on.

Conclusion

Every question in this list came from a system somebody had to build and then keep alive at 3 a.m., so the more of that you do, the less the interview feels like a performance and the more it feels like describing your Tuesday. Run a side project with a real queue in it, volunteer for the on-call rotation, ask to sit in on a design review even when the design isn't yours.

And if you want structured ground to cover between now and your next loop, these go deeper on the pieces these answers lean on:

Josep Ferrer

Auteur

Josep Ferrer

Josep is a freelance Data Scientist specializing in European projects, with expertise in data storage, processing, advanced analytics, and impactful data storytelling. 

As an educator, he teaches Big Data in the Master’s program at the University of Navarra and shares insights through articles on platforms like Medium, KDNuggets, and DataCamp. Josep also writes about Data and Tech in his newsletter Databites (databites.tech). 

He holds a BS in Engineering Physics from the Polytechnic University of Catalonia and an MS in Intelligent Interactive Systems from Pompeu Fabra University.

FAQs

What do interviewers actually look for in a system design interview?

Structure and tradeoffs. Can you clarify the problem, put rough numbers on it, draw something sane, and explain why you picked one option over another. The "right" architecture matters far less than the reasoning.

How long should I spend on clarifying questions?

Five minutes, tops. Long enough to know the scale, the read/write mix, and what "done" looks like.

Do I need to know Kafka, Redis, and Kubernetes by name?

Not by name, but you need the ideas behind them (a durable log, a fast in-memory store, a way to run and scale containers). If you name a tool, be ready to say what it does and what it costs you. Saying "a message queue" is perfectly fine at beginner and intermediate level.

Are system design questions different for data engineers?

Yes, quite a bit. You get asked about pipelines, batch versus streaming, backfills, and data quality rather than API gateways. The framework is the same, though: requirements, numbers, design, tradeoffs, failure modes.

How many questions should I practice before an interview?

Honestly, ten done properly beats forty skimmed. Pick a few from your level, a few from your role, and rehearse them out loud with a timer.

Onderwerpen

Gerelateerd