Back to System design

System Design Trade-offs Cheat Sheet

easy
All
FrameworkTrade-offs

Every system design decision is a trade, and saying which side you took — and what it cost — is most of what separates a senior answer from a confident one. This page is the short list of trades that come up in almost every interview, with the sentence that shows you understand each.

Key Concepts

1
There is no such thing as a free choice, only an appropriate one. Interviewers are not looking for the "correct" option; they are listening for whether you know what you gave up. "I'll use eventual consistency" is a weak answer. "I'll use eventual consistency because a stale follower count for two seconds is invisible, and the alternative costs a cross-region round trip on every write" is a strong one.
There is no such thing as a free choice, only an appropriate one.
2
Name the trade before you are asked about it. Volunteering "the cost of this is X" removes the interviewer's need to probe, and it is the clearest available signal that you have run systems rather than only read about them.
Name the trade before you are asked about it.
3
Most trades reduce to four currencies: latency, consistency, cost and complexity. Almost every decision spends one to buy another. When you get lost in an argument, work out which currency you are spending.
Most trades reduce to four currencies:
4
Beware the trades that are not trades. Some choices are strictly worse and only look balanced: rolling your own consensus, storing money in floats, retrying non-idempotent operations, caching without a bounded staleness. Recognising those is as valuable as balancing the real ones.
Beware the trades that are not trades.
5
What the interviewer is probing.
What the interviewer is probing.
6
1. "Give a trade-off you have actually made." Probing: whether this is lived or memorised. Stalls: "Consistency versus availability." Moves up: a specific one with the context and what it cost — a named decision with its downside is far more convincing than the abstract pair.
1. "Give a trade-off you have actually made."
7
2. "What does CAP actually say?" Probing: precision, because it is widely misquoted. Stalls: "Pick two of three." Moves up: under a network partition you choose consistency or availability — outside a partition it says nothing, which is why PACELC is the more useful framing.
2. "What does CAP actually say?"
8
3. "When is eventual consistency unacceptable?" Probing: judgement. Stalls: "It always works." Moves up: where a stale read causes real harm — account balances before a transfer, inventory at checkout, permission checks.
3. "When is eventual consistency unacceptable?"
9
4. "How do you answer a which-would-you-choose question?" Probing: the technique. Stalls: "Pick the better one." Moves up: name the deciding factor first, then choose — the reasoning is the answer, and a choice without it scores nothing.
4. "How do you answer a which-would-you-choose question?"

The trades that come up constantly

  Strong vs eventual consistency
    Buys: correctness under concurrency / lower latency and higher
          availability
    Costs: a round trip to a quorum / stale reads the app must
          tolerate
    Say: "Eventual here because a two-second stale count is
          invisible, and a quorum write costs 60 ms cross-region."
  Normalised vs denormalised
    Buys: one source of truth, cheap writes / fast reads, no joins
    Costs: joins at read time / update fan-out and drift
    Say: "Denormalised, because this is read 100x more than written,
          and I'll keep the write path fixing all copies."
  Sync vs async processing
    Buys: immediate result, simple errors / responsiveness, buffering
    Costs: caller waits for the slowest dependency / eventual
          completion the UI must represent
    Say: "Async, and the client shows 'processing' -- the alternative
          couples checkout latency to the email provider."
  Cache vs no cache
    Buys: latency and origin protection
    Costs: staleness, invalidation bugs, a new failure mode
    Say: "Cached with a 30 s TTL; a stale price for 30 s is
          acceptable, a stale balance is not."
  Monolith vs services
    Buys: simple deploys and local transactions / independent scaling
          and teams
    Costs: coupled releases / network calls, partial failure,
          distributed debugging
    Say: "Monolith until the team or the scaling profile forces a
          split; the first service to extract is the one with a
          different scaling shape."
  SQL vs NoSQL
    Buys: joins, transactions, ad-hoc queries / horizontal writes
    Costs: harder horizontal scaling / queries fixed at design time
    Say: "PostgreSQL until measured limits; the access pattern here
          is not known well enough to fix a partition key."
  Push vs pull
    Buys: low latency, no wasted polls / simple, resilient clients
    Costs: connection state and fan-out cost / latency and load
    Say: "Push for chat, pull for a dashboard refreshed every
          minute."
  Replication vs sharding
    Buys: read scale and redundancy / write scale and dataset size
    Costs: no write scale, lag / cross-shard queries, resharding
    Say: "Replicas first -- they solve reads without giving up
          joins. Shard when writes or size force it.

Choices that are not trade-offs

These look like judgement calls and are not:

  Rolling your own consensus
    The algorithm is describable in a page and unpleasant in the
    details. Use etcd, ZooKeeper or a library.
  Money in floating point
    0.1 is not representable. Integer minor units, always.
  Retrying non-idempotent operations
    A retried payment is a second payment. Idempotency key first,
    retries second.
  Caching without bounded staleness
    "We'll invalidate on write" plus a missed path equals a stale
    value forever. A TTL is the backstop that makes the bug
    temporary.
  Logging secrets "temporarily"
    Logs outlive intentions and spread to systems with different
    access rules.
  Dual writes to two datastores
    They fail independently. Use an outbox and make one store
    authoritative.
  Unbounded queues
    A queue with no limit converts a throughput problem into an
    out-of-memory crash plus unbounded latency. Bound it and decide
    what to shed.
  Health checks that never fail
    A check that returns 200 without touching a dependency will
    report a dead service as healthy.