Start here: 'Design X' is unbounded until you fix the numbers#
TL;DRthe 30-second version
- Non-functional requirements (NFRs) are the quality targets a system must hit: how much scale, how low the latency, how high the availability, how strong the consistency, how durable the data.
- They're not paperwork. Every later choice β SQL or NoSQL, one region or many, sync or async replication, cache or no cache β is picked to satisfy some NFR. Skip them and every choice is a guess you can't defend.
- You derive them from the product, not from ambition. A payment needs different targets than a like count, and asking for more than the product needs over-builds the system and burns money.
- The rule that runs through all of it: pick the weakest target that still meets the real need. Every extra nine of availability, every step from eventual to strong consistency, costs latency, money, and complexity.
An interviewer says 'Design Twitter.' If you open your mouth and start naming databases, you've already lost, because you don't yet know what you're designing. Twitter for a thousand internal users fits on one server with a plain SQL database. Twitter for 300 million daily users needs sharding, caching, fan-out pipelines, and multiple data centers. Same feature list, opposite machines. The feature list didn't tell you which one to build. The numbers did.
Those numbers come from five questions, and you should ask them out loud before you draw a single box. How much scale β how many users, how many reads and writes per second, how much data, growing how fast? How fast β what response time do users actually feel, and where does it start to hurt? How available β how much downtime a year can the product survive? How consistent β when two people read the same thing at the same moment, must they see the identical value, or is a slightly stale answer fine? How durable β if a disk dies, can you afford to lose any of this data, and how much? Answer those five and the problem stops being 'Design Twitter' and becomes 'Design a system that serves 200,000 reads per second at under 200 milliseconds, stays up 99.9% of the year, and never loses a posted tweet.' That second sentence you can actually engineer.
The NFR menu, one line each#
There's a short, standard menu of non-functional requirements. You won't quote all of them for every problem β you pick the two or three that dominate β but you should know each by name and be able to make it concrete. Vague targets ('it should be fast, and scalable') are worthless; a target is only useful once it's a number.
- Scale β the size of the load. Measured in daily active users (DAU, the count of distinct users in a day), reads and writes per second (QPS, queries per second), total data stored, and the growth rate. Everything else is sized off these numbers.
- Latency β how long one request takes, from the user's point of view. Quoted as percentiles: p50 (the median, the time half of requests beat) and p99 (the time 99% of requests beat, i.e. the slow tail). Rough human thresholds: under ~100 ms feels instant, ~1 second is a noticeable pause, past a few seconds users leave.
- Availability β the fraction of time the system is up and serving. Quoted in 'nines': 99.9% ('three nines'), 99.99% ('four nines'). Each extra nine cuts allowed downtime by 10x and costs far more than the last.
- Consistency β whether every reader sees the latest write. Strong (also called linearizable) means a read always returns the most recent write, as if there were one copy. Eventual means copies converge after a short delay, so a read can briefly return stale data. Which one you need is per-feature, not per-system (see the consistency-models topic for the full spectrum).
- Durability β the promise that committed data survives failures. A disk dies, a data center loses power β is any acknowledged write allowed to vanish? Sized with RPO (recovery point objective: how much recent data you can afford to lose, e.g. 'up to 5 minutes') and RTO (recovery time objective: how long you can be down before recovering).
- Throughput β the sustained volume the system processes, e.g. writes per second ingested or messages per second delivered. Latency is 'how long one request takes'; throughput is 'how many you handle at once.' A system can be low-latency and low-throughput, or the reverse.
- Cost β the budget, in machines and dollars, that all of the above has to fit inside. It's the constraint that stops you from just buying more nines. Every target above is really 'the best I can do for this money.'
Two of these you should compute in front of the interviewer rather than guess, because the arithmetic is the point. Scale in QPS falls out of DAU. Say 10 million daily active users, each doing 20 writes a day: that's 200 million writes a day, and 200,000,000 divided by 86,400 seconds is about 2,300 writes per second on average. Traffic isn't flat, so multiply by a peak factor of 3 to 5 for the busy hour β call it roughly 10,000 writes per second at peak. Reads usually dominate writes by 10x or more, so reads land near 100,000 per second. Those three numbers β average write QPS, peak QPS, read QPS β decide whether one database survives or you need sharding and caches. Deriving them out loud, instead of asserting 'it's high scale,' is the difference between engineering and hand-waving.
The two tables you must know cold#
Two lookup tables come up in almost every interview, and fumbling them reads as not having done the reps. The first turns an availability target into concrete downtime. When you say 'four nines,' you're promising the system is down no more than about 52 minutes across an entire year β know what each nine actually buys.
| Availability | Nickname | Downtime per year | Downtime per day |
|---|---|---|---|
| 90% | one nine | 36.5 days | 2.4 hours |
| 99% | two nines | 3.65 days | 14.4 minutes |
| 99.9% | three nines | 8.77 hours | 1.44 minutes |
| 99.99% | four nines | 52.6 minutes | 8.6 seconds |
| 99.999% | five nines | 5.26 minutes | 0.86 seconds |
Read the table as a cost curve, not a menu of equals. Going from 99% to 99.9% removes a couple of days of downtime and is often just good engineering β health checks, retries, a standby. Going from 99.99% to 99.999% removes about 47 minutes over a whole year, and buying it means redundant everything, multi-region failover, and automation that recovers in seconds because no human can react inside a five-minute annual budget. The last nine can cost more than all the previous ones combined, which is exactly why you don't reach for five nines by reflex.
PredictA feature needs 99.99% availability. Roughly how much downtime a year is that, and what does buying the next nine (99.999%) actually cost you?
Hint: Each nine cuts downtime ~10x; what has to change operationally when a human can no longer react inside the budget?
99.99% is about 52 minutes of downtime a year (four nines). The next nine, 99.999%, drops that to about 5 minutes a year β you're removing roughly 47 minutes of annual downtime. The cost is steep and structural: at a 5-minute yearly budget, no on-call human can even log in and diagnose in time, so recovery has to be fully automated. You need redundancy with no single point of failure, health checks that detect a fault in seconds, and automatic failover β often across regions, which drags in cross-region replication and its own latency and consistency costs. So the honest interview answer is: the extra nine buys ~47 minutes a year and costs a large multiple in infrastructure and operational complexity, so only ask for it when the product genuinely can't tolerate an hour of downtime (payments, telecom, some infrastructure). For most features, three or four nines is the right target.
The second table is about why you quote latency as p99 and not as an average. The average hides the tail β the slow requests β and the tail is exactly what users remember. Take a service where 99 out of 100 requests return in 20 ms and 1 returns in 2,000 ms. The average is about 40 ms, which looks great and is a lie: one in every hundred users waited two full seconds. The average smeared that pain across everyone until it disappeared. Percentiles refuse to hide it.
| Metric | What it means | Why it matters |
|---|---|---|
| p50 (median) | Half of requests are faster than this | The typical experience; says nothing about the tail |
| p90 | 90% of requests are faster than this | Starts to expose the slow requests the average hid |
| p99 | 99% of requests are faster than this | The tail every heavy user hits; the number you commit to |
| p99.9 | 99.9% are faster than this | Rare stalls; matters when one page makes many calls |
| average | Total time divided by request count | Misleading β a few slow requests barely move it |
The tail matters more the bigger you get, because of a simple multiplication. Suppose loading one page makes 100 backend calls, and each call independently has a 1% chance of hitting the slow p99 path. The chance that all 100 are fast is 0.99 to the 100th power, about 37%. So roughly 63% of page loads touch at least one slow call. A tail that hits '1 in 100 requests' becomes 'the majority of page loads' once a page fans out. That's why serious systems commit to a p99 target, not an average β and why 'our average latency is 40 ms' is a number that should make an interviewer suspicious, not satisfied.
Every target has a price β pick the weakest that works#
NFRs are not free wishes; each one you tighten spends something real. The skill isn't asking for a lot β anyone can ask for a lot. The skill is asking for the least the product can live with, because the least is the cheapest and simplest thing that still works.
- Each extra nine of availability costs a multiple in money and complexity: more replicas, more regions, more automation, more things that can themselves break.
- Strong consistency costs latency and availability. To guarantee every reader sees the latest write, the copies must coordinate before answering, which adds round-trips and means a network partition can force the system to reject writes rather than diverge.
- Lower latency usually costs money and consistency: caches, read replicas, and edge locations cut response time but serve data that can be slightly stale.
- Higher durability costs latency and throughput: waiting for a write to be safely replicated to several machines before acknowledging is safer and slower than acknowledging from one.
- Over-specifying any target over-builds the system. Five nines and strong-everywhere on a feature that needed three nines and eventual consistency means a machine that's more expensive, more complex, and more failure-prone than the product ever required.
The consistency-vs-availability tension has a name worth dropping once, plainly. CAP says that during a network partition (when parts of the system can't talk to each other) you must choose: stay consistent and refuse some requests, or stay available and serve possibly-stale data. PACELC spells the whole trade out: if there's a Partition, choose Availability or Consistency (that's CAP); Else β in normal operation, no partition β you still trade Latency against Consistency, because stronger consistency means more coordination means slower responses. So consistency isn't only a partition-time question; it's a tax on latency all the time.
All of which collapses into one rule you can say out loud and then apply to every feature: pick the weakest target that still meets the product need. Not the strongest you can imagine β the weakest that's genuinely acceptable. Then, when you tighten one deliberately (this balance must be strongly consistent), you can name exactly what you're paying for it, which is precisely the reasoning an interviewer is listening for.
PredictA candidate says 'I'll make the whole system strongly consistent to be safe,' including the like counts on posts. What's wrong with that, and what should they do instead?
Hint: What actually breaks if a like count is stale for one second, versus if an account balance is?
'To be safe' is the tell that no requirement was derived β safety was assumed instead of justified. Strong consistency for like counts is paying a real cost for a benefit nobody needs. A like count being off by one for a second harms no one, so it's a textbook fit for eventual consistency: count asynchronously, let the number converge, and keep the write path cheap and always-available. Forcing strong consistency there means every like has to coordinate across replicas before it's acknowledged, adding latency and creating a feature that can refuse writes during a partition β a worse product, for no gain. The right move is per-feature: strong (linearizable) consistency for the things where a stale read causes real harm (account balances, inventory you can oversell, a username you can't double-assign), and eventual consistency for the things where it doesn't (like counts, view counts, follower lists, feeds). Naming that split, and justifying each side from the product, is the strong answer.
Same system, different targets per surface#
The clearest sign a candidate understands NFRs is that they refuse to give the whole system one set of numbers. A real product is several surfaces with different needs, and the targets are per-surface. The two axes this shows up on most are consistency and latency.
| Surface | Consistency needed | Latency profile | Why |
|---|---|---|---|
| Bank balance / payment | Strong (linearizable) | Latency-critical, synchronous | A stale or double-spent balance is real financial harm |
| Username / unique handle | Strong | Synchronous check on signup | Two people can't be granted the same handle |
| Like / view count | Eventual | Latency-critical write, lazy converge | Off-by-one for a second harms nobody |
| Social feed / timeline | Eventual | Latency-critical read (cache/edge) | A slightly stale feed is fine; speed matters more |
| Analytics / reporting | Eventual (batch) | High throughput, latency-relaxed | Numbers can lag minutes; volume is what matters |
Notice the same distinction repeats. Where a stale read causes harm (money, uniqueness), you pay for strong consistency and synchronous latency. Where it doesn't (counts, feeds), you take eventual consistency and spend your budget on speed instead. And the latency axis splits the same system too: the user-facing read path is latency-critical and measured in milliseconds, while the analytics pipeline behind it is a batch job measured in throughput β it can take minutes as long as it processes everything. One product, several NFR profiles, each derived from what that surface actually needs.
Three worked target sets
Here are three surfaces with the NFRs you'd actually state for each. They live in the same company and share almost no targets.
| NFR | Payment path | Social feed | Analytics pipeline |
|---|---|---|---|
| Consistency | Strong / linearizable | Eventual | Eventual (batch) |
| Availability | 99.99%+ | 99.9% | 99% (internal) |
| Latency target | p99 under ~300 ms | p99 under ~150 ms (read) | Minutes-to-hours is fine |
| Durability | Zero loss, RPO = 0 | Some loss tolerable | Reprocessable from source |
| Optimized for | Correctness | Read latency | Throughput |
- Payment path: correctness dominates. Strong consistency so no balance is double-spent, near-zero data loss (RPO = 0, every committed payment survives), and high availability because an outage is lost revenue and trust. You pay for it with synchronous replication and its latency.
- Social feed: latency dominates. Reads massively outnumber writes, so you cache and read-replica hard, accept eventual consistency (a feed stale by a second is invisible), and a brief outage is annoying but survivable at three nines.
- Analytics pipeline: throughput dominates. It ingests huge volumes, can lag minutes or hours, and if a batch fails you re-run it from the source data β so durability of the pipeline's own state barely matters and availability can be the lowest of the three.
Pitfalls & gotchas
Should I just ask for five nines to be safe?
No β that's the most common NFR mistake. Five nines (about 5 minutes of downtime a year) demands multi-region redundancy and fully automated failover, and costs a large multiple over three or four nines. Ask what the product can actually tolerate. Most user-facing features are perfectly fine at 99.9% (about 9 hours a year). Reserve four or five nines for the surfaces where an outage is genuinely catastrophic, like payments or core infrastructure.
Is quoting average latency fine if it's low?
No. The average hides the tail. A 40 ms average can conceal that 1% of requests take 2 seconds, and that 1% is what heavy users and multi-call pages hit constantly. Always commit to a percentile β p99 is the standard β so the slow tail is visible and accountable rather than smeared away.
Can I just say 'high scale' instead of computing QPS?
Not convincingly. 'High scale' is a feeling; QPS is a number, and it's derivable in ten seconds. Start from DAU, multiply by actions per user per day, divide by 86,400 seconds, apply a peak factor, and split reads from writes. That arithmetic is what decides whether one database survives or you need sharding β skipping it means every capacity decision after it is a guess.
Why not make everything strongly consistent so I never have to think about staleness?
Because strong consistency is a tax on latency and availability that most features don't need to pay. Coordinating every replica before answering adds round-trips and lets a network partition block writes. Pick strong consistency only where a stale read causes real harm (balances, inventory, unique IDs) and take eventual consistency everywhere else β the choice is per-feature.
Is all my data equally important to keep?
Almost never, and treating it as if it were over-builds the system. A committed payment must never be lost (RPO = 0). A cache entry can vanish and be recomputed. Derived analytics can be re-run from the raw source. Tier your durability: spend the expensive synchronous replication on the data whose loss is unrecoverable, not on data you can rebuild.
QuizA candidate designing a photo-sharing app opens with: 'It'll be five nines available, strongly consistent everywhere, and average latency under 50 ms.' What's the single biggest problem with this framing?
- The latency target is too slow for photos.
- They specified maximal targets without deriving any of them from the product, so each one is an unjustified cost β and quoting an average hides the tail.
- Five nines isn't achievable for a photo app.
- They forgot to mention throughput, which is the only NFR that matters.
Show answer
They specified maximal targets without deriving any of them from the product, so each one is an unjustified cost β and quoting an average hides the tail. β The problem isn't any single number β it's that every number was maximized by reflex instead of derived from what a photo-sharing app needs. Five nines and strong-everywhere are expensive commitments a photo feed almost certainly doesn't require: a feed can be eventually consistent (a like or a new photo appearing a second late harms no one) and three nines is plenty for a social product. Asking for the maximum everywhere over-builds the system, costs a fortune, and β because none of it was justified from the product β signals guessing rather than engineering. On top of that, 'average latency under 50 ms' hides the tail; the right target is a p99. The other options nitpick individual numbers; the real miss is the un-derived, over-specified framing.
In an interview
NFRs are the first few minutes of the interview and they set the tone for everything after. Do them out loud, derive the numbers, and then keep referring back to them β the strongest candidates treat the NFR list as the spec they're building against, not a box they ticked at the start.
- State the NFRs early and out loud, before drawing anything. Walk the five questions: scale, latency, availability, consistency, durability. Make each a number, not an adjective.
- Derive, don't assert. Compute QPS from DAU in front of the interviewer; quote availability as downtime from the nines table; quote latency as a p99. Showing the arithmetic is the point.
- Justify each target from the product. 'Strong consistency on the balance because a double-spend is real money; eventual on the like count because off-by-one for a second is harmless.' Every number gets a reason.
- Pick the weakest target that works, and say so. Reaching for five nines or strong-everywhere by default is the classic tell of guessing; deriving the minimum acceptable is the tell of engineering.
- Revisit the NFRs at the deep dive. When a design choice trades one off β a cache that adds staleness, a second region that adds write latency β name which NFR you're spending and which you're buying. That callback is what separates a strong candidate from a competent one.
PredictHalfway through, you add a read replica to cut read latency, and the interviewer asks 'any downside?' How do you tie the answer back to your NFRs?
Hint: A replica lags the primary β which NFR does that spend, and which of your per-feature targets says whether that's allowed?
Tie it straight to the consistency target you set earlier. A read replica lags the primary slightly, so reads served from it can be stale β you've traded consistency for latency. Then reference the per-feature decision you already made: that's fine for the feed and view counts, where you declared eventual consistency acceptable, so route those reads to the replica. But for anything you marked strongly consistent (the balance, a just-changed setting the user expects to see immediately), keep reading from the primary so you don't serve a stale value. The strong answer names the exact NFR being spent (consistency), the one being bought (read latency), and points back to the per-feature targets you stated up front to decide which reads can safely use the replica. That callback β 'this is the trade I flagged earlier' β is what shows the NFRs were a real spec, not decoration.
References
- Google SRE Book β Service Level Objectives β SLIs, SLOs, and error budgets β the rigorous version of turning availability and latency into targets.
- Google SRE Book β Embracing Risk β Why 100% availability is the wrong target and how much each nine actually costs.
- Designing Data-Intensive Applications (Kleppmann) β Chapter 1 on reliability, scalability, and maintainability; the p99/tail-latency argument is here.
- System Design Interview, Vol. 1 (Alex Xu) β The back-of-envelope estimation chapter β deriving QPS and storage from DAU, interview-style.