Non-functional Requirements
Overview
Functional requirements describe what a system does, "users can shorten a URL," "the system sends notifications," "drivers can accept ride requests." Non-functional requirements (NFRs) describe how well the system does it, how available it must be, how fast it must respond, how consistent the data must be, how much data loss is acceptable in a failure.
NFRs are often the most consequential inputs to a system design. Two systems with identical functional requirements but different NFRs can require completely different architectures. A social media feed that tolerates eventual consistency can be built on a fanout architecture that would be catastrophic for a bank transaction system requiring strong consistency. A real-time messaging app targeting p99 latency under 100ms makes different component choices than a batch analytics pipeline where 30-second delays are acceptable.
This is why interviewers probe NFRs explicitly in the first minutes of a system design interview. Candidates who surface NFRs proactively, without being prompted, demonstrate the kind of senior thinking that separates L5/L6 engineers from juniors. They are showing that they understand the system's constraints before proposing a solution.
This lesson teaches you how to identify, quantify, and reason about the most important NFRs: availability, consistency, durability, latency, and throughput. It introduces the vocabulary, SLAs, SLOs, SLIs, CAP theorem, and, most importantly, shows you how to connect NFRs to the specific component choices they justify.
Core Concepts
Availability and the "Nines"
Availability is the fraction of time a system is operational and accessible to users. It is typically expressed as a percentage, often referred to as "nines."
| Availability | Downtime per year | Downtime per month | Downtime per week |
|---|---|---|---|
| 99% (two nines) | ~3.65 days | ~7.3 hours | ~1.7 hours |
| 99.9% (three nines) | ~8.76 hours | ~43.8 minutes | ~10.1 minutes |
| 99.99% (four nines) | ~52.6 minutes | ~4.4 minutes | ~1.0 minute |
| 99.999% (five nines) | ~5.26 minutes | ~26 seconds | ~6 seconds |
What does each level mean in practice? Three nines (99.9%) allows about 10 minutes of downtime per week, acceptable for an internal tool. Four nines (99.99%) allows under 5 minutes of downtime per month, appropriate for a customer-facing payment flow. Five nines (99.999%) is the standard for critical infrastructure like telephony.
Achieving higher availability requires redundancy, health checks, automatic failover, and geographic distribution. Each additional nine is exponentially more expensive to maintain. Candidates who ask "what availability do we need?" before proposing active-active multi-region redundancy demonstrate cost-aware engineering.
Availability is calculated across dependent components. If your system has three components each at 99.9% availability, the overall system availability is 99.9% × 99.9% × 99.9% ≈ 99.7%. Chaining dependencies degrades availability, another reason to minimize synchronous dependencies in the critical path.
Consistency Models
Consistency describes what guarantees users have about the state they see in a distributed system.
Strong consistency means every read receives the most recent write or an error. The database behaves as if there is only one copy. This is what you get with a single Postgres node. Achieving strong consistency across distributed nodes is expensive, it requires coordination protocols (two-phase commit, Raft) that add latency.
Eventual consistency means that, given enough time and no new writes, all replicas will converge to the same value. Reads may return stale data. This is what you get with many NoSQL databases, DNS propagation, and social media feeds. Eventual consistency enables high availability and low latency at the cost of stale reads.
Causal consistency sits between the two: if operation B is causally dependent on operation A, every process that sees B will also see A. This preserves cause-and-effect ordering without requiring total ordering across all operations. Some distributed databases (Spanner, CockroachDB) approximate this with version-stamped reads.
In interviews, state the consistency requirement early: "This is a bank ledger, so we need strong consistency, no user should see a wrong balance." Or: "This is a social feed, so eventual consistency is fine, a post appearing a second late is acceptable." The choice has cascading effects on your component selection.
The CAP Theorem
The CAP Theorem states that a distributed system can guarantee at most two of three properties:
- Consistency (C): every read receives the most recent write or an error
- Availability (A): every request receives a (possibly stale) non-error response
- Partition Tolerance (P): the system continues operating even when network partitions occur
Network partitions are unavoidable in real distributed systems, the only question is how you respond to them. Therefore, the practical choice is between CP and AP:
- CP systems (HBase, Zookeeper, traditional RDBMS with distributed coordination): sacrifice availability during a partition to preserve consistency. The system may return errors rather than stale data.
- AP systems (Cassandra, DynamoDB in default mode, CouchDB): sacrifice consistency during a partition to remain available. The system may return stale data rather than errors.
- CA systems (single-node Postgres, MySQL without replication): abandon partition tolerance, only work in a single-node or trusted network environment.
The CAP theorem is a simplification. Modern systems (Google Spanner, AWS Aurora Global) blur these boundaries using techniques like synchronized clocks and quorum reads. In interviews, use the CAP framing to justify your database and replication choices, then acknowledge that real-world systems find nuanced positions.
Durability and Data Loss Tolerance
Durability means that once a write is committed, it persists even through hardware failure, power loss, or crash. ACID-compliant databases guarantee durability by writing to disk before acknowledging the commit.
The key NFR question is: "How much data loss is acceptable if the system fails?" This is expressed as RPO (Recovery Point Objective), the maximum amount of data loss measured in time. RPO = 0 means zero data loss. RPO = 1 hour means losing up to 1 hour of writes is acceptable.
Related: RTO (Recovery Time Objective), the maximum acceptable time to recover from a failure. RTO = 15 minutes means the system must be restored within 15 minutes of a failure.
Durability trade-offs:
- Writing synchronously to multiple replicas (strong durability) increases write latency.
- Writing asynchronously to replicas (lower durability) reduces write latency but risks losing recent writes on failure.
- Write-ahead logging (WAL) in Postgres and similar databases provides durability with moderate overhead.
In interviews, mention durability when designing storage-heavy systems. "For this financial ledger, RPO = 0, we cannot lose any committed transaction, so we need synchronous replication to at least two nodes."
Latency Targets and Percentiles
Latency is the time from when a client sends a request to when it receives a response. Raw latency numbers are less useful than percentile distributions:
- p50 (median): 50% of requests complete within this time. Most users experience at most this latency.
- p95: 95% of requests complete within this time. The tail of the distribution starts here.
- p99: 99% of requests complete within this time. Your slowest 1% of users experience at most this latency.
- p999 (three nines percentile): 99.9% of requests complete within this time. Relevant for services with very large user bases where even 0.1% of users represents millions of people.
Why percentiles matter: your p50 latency might be 10ms, but your p99 might be 500ms if you have occasional database index misses or garbage collection pauses. High p99 latency signals architectural problems, hot partitions, synchronous calls to slow services, missing caches. Interviewers value candidates who distinguish "average" latency from "tail" latency.
Latency budget allocation: a request path has multiple hops, each contributing latency. If your SLO is p99 under 200ms, you need to allocate that budget across CDN lookup, load balancer, application server, cache, and database. A database query that takes 150ms on a cache miss leaves only 50ms for everything else.
Throughput and Capacity Planning
Throughput is the number of operations a system can handle per unit of time, typically queries per second (QPS), requests per second (RPS), or messages per second. Throughput and latency are related but distinct: a system can have high throughput (processing many concurrent requests) while still having high per-request latency (each request takes long but many are processed in parallel).
Throughput bottlenecks appear at the weakest link. If your application servers can handle 10,000 QPS but your database can only handle 2,000 QPS, your system throughput is 2,000 QPS. Caching eliminates database calls for hot data, dramatically increasing effective throughput without changing the database's physical capacity.
SLAs, SLOs, and SLIs
These three terms form a hierarchy used by production engineering teams to operationalize reliability:
SLI (Service Level Indicator), A quantitative measure of a service's behavior. Examples: request latency, error rate, throughput, availability. SLIs are the raw metrics you collect.
SLO (Service Level Objective), An internal target for an SLI. "p99 latency must be under 200ms for 99.9% of requests over a 30-day rolling window." SLOs are internal commitments that drive engineering decisions.
SLA (Service Level Agreement), A contractual commitment made to customers that includes remedies (refunds, credits) if the SLO is violated. SLAs are almost always less strict than internal SLOs, you need headroom so that internal degradation does not automatically trigger customer contracts.
In interviews, use "SLO" when discussing internal targets and "SLA" when discussing customer-facing commitments. Saying "our SLO is 99.99% availability, which gives us a safety margin above the 99.9% SLA we commit to customers" signals operational maturity.
Trade-off Pairs
The most important trade-off pairs in system design:
Availability vs. Consistency (CAP): choosing AP (Cassandra, DynamoDB) gives you availability during partitions at the cost of stale reads. Choosing CP (Postgres with synchronous replication) preserves consistency but may reject requests during partitions.
Latency vs. Durability: synchronous replication to two replicas before acknowledging a write increases durability but adds the round-trip latency of the secondary replica. Asynchronous replication reduces write latency but risks data loss on primary failure.
Cost vs. Redundancy: adding a standby database replica in a second region doubles your database cost. Five nines availability often requires at least two regions. Be explicit about cost trade-offs in interviews, it signals business awareness.
Consistency vs. Throughput: strong consistency (quorum writes) reduces throughput because each write requires agreement from multiple nodes. Eventual consistency (single-node writes with async replication) maximizes throughput.
Mermaid Diagram 1: CAP Theorem Triangle
graph TD
CAP["CAP Theorem\n(pick 2 of 3 in a distributed system)"]
C["Consistency\nEvery read returns\nthe most recent write"]
A["Availability\nEvery request gets\na non-error response"]
P["Partition Tolerance\nSystem works despite\nnetwork partitions"]
CP["CP Systems\nHBase, Zookeeper\nPostgres + sync replication\n\nSacrifices: Availability\nduring network partition"]
AP["AP Systems\nCassandra, DynamoDB\nCouchDB\n\nSacrifices: Consistency\n(stale reads allowed)"]
CA["CA Systems\nSingle-node Postgres\nMySQL no replication\n\nSacrifices: Partition Tolerance\n(not distributed)"]
CAP --> C
CAP --> A
CAP --> P
C & P --> CP
A & P --> AP
C & A --> CA
Mermaid Diagram 2: Latency Budget Allocation Across a Request Path
graph LR
Client["Client\n(browser / app)"]
CDN["CDN Edge\n+5ms"]
LB["Load Balancer\n+1ms"]
App["App Server\n+10ms\n(auth, validation)"]
CacheHit["Cache Hit\n+2ms total"]
CacheMiss["Cache Miss\n+80ms (DB round-trip)"]
DB["Database\n+75ms\n(query + disk I/O)"]
Response["Response\nTotal budget: 200ms p99"]
Client -->|"DNS + TCP: ~10ms"| CDN
CDN --> LB
LB --> App
App -->|"check Redis"| CacheHit
App -->|"on miss"| CacheMiss
CacheMiss --> DB
DB -->|"return row"| CacheMiss
CacheMiss -->|"populate cache"| App
CacheHit --> Response
App --> Response
Interview Application
Surfacing NFRs in the First 2-3 Minutes
The pattern that signals seniority: after hearing the problem statement, ask three categories of NFR questions before touching the whiteboard.
Scale questions: "How many daily active users are we targeting? What's the expected read-to-write ratio? Are there traffic spikes we need to handle?"
Reliability questions: "What availability target do we need, three nines, four nines? How much data loss is acceptable in a failure scenario? Do we need multi-region redundancy?"
Consistency questions: "If two users update the same record concurrently, which wins? Can users see slightly stale data, or do they need real-time accuracy?"
These questions are not box-checking, they actively change your design. If the interviewer says "four nines required," you know you need redundancy. If they say "eventual consistency is fine," you can use simpler, higher-throughput storage. If they say "RPO = 0," you know you need synchronous replication.
Using NFRs to Justify Component Choices
Every component you introduce should trace back to an NFR. This is the most powerful move in a system design interview, connecting your requirements to your decisions.
Examples:
- "We need 99.99% availability, so I'm putting a read replica in a second availability zone. If the primary fails, we can fail over within our RTO of 5 minutes."
- "The consistency model here is eventual, users posting to a social feed can tolerate a 1-2 second propagation delay. That lets us use async replication, which gives us much higher write throughput."
- "Our p99 latency target is 100ms. A database call on cache miss takes 50-80ms, which leaves very little budget. That's why I'm caching the 20% of content that accounts for 80% of reads, the cache hit rate should be around 90%."
Framing Trade-offs as Senior Thinking
When you introduce a design choice, follow it immediately with the trade-off. This framing pattern demonstrates senior thinking:
"I'm choosing [X] because [NFR reason]. The trade-off is [cost/limitation], which is acceptable because [context]."
Example: "I'm choosing asynchronous replication because our write throughput requirement of 10,000 QPS would be difficult to sustain with synchronous quorum writes, the added latency per write would compound under load. The trade-off is that in a primary failure, we might lose the last second of writes. Given that this is a social timeline and not a financial ledger, that's an acceptable RPO."
Common Mistakes
Stating availability targets without understanding what they mean in downtime. Saying "we need five nines" without knowing that this means under 6 seconds of downtime per week, and what it takes architecturally to achieve it, signals that you are cargo-culting the term. Always be able to translate a "nines" number into concrete downtime and explain what redundancy achieves it.
Conflating consistency models. "Eventual consistency" is not the same as "no consistency." Stale reads for 1-2 seconds is very different from stale reads for 30 minutes. When you say "eventual consistency," qualify the expected propagation delay. Similarly, do not say "strong consistency" when you mean "read-your-own-writes consistency", these are meaningfully different guarantees.
Ignoring durability. Candidates often design for availability and latency while forgetting to ask how much data loss is acceptable. A system that is highly available but loses the last 10 minutes of writes on a crash may be unacceptable for the problem. Ask about RPO explicitly.
Picking "five nines" without justifying the cost. Five nines availability is expensive, active-active multi-region replication, automatic failover, global load balancing. If the problem is an internal analytics dashboard, proposing five nines is over-engineering. Match the reliability tier to the business criticality of the system.
Not connecting NFRs to component decisions. If you list NFRs in the requirements phase and then never reference them again when choosing components, the interviewer will note the disconnect. Every major component choice should be traceable to an NFR.
Key Vocabulary
Availability, The fraction of time a system is operational. Expressed as a percentage ("nines"). 99.9% availability means roughly 8.76 hours of downtime per year. In interviews, state the target before proposing redundancy strategies: "We need 99.99%, which means less than 52 minutes of downtime per year."
Consistency (strong), Every read returns the most recent committed write. No stale data. Requires coordination across distributed nodes, which adds latency. In interviews: "Bank transactions need strong consistency, a user must never see an incorrect balance."
Consistency (eventual), All replicas will converge to the same value eventually, given no new writes. Reads may be stale. Enables high availability and write throughput. In interviews: "A social media timeline can tolerate eventual consistency, a post appearing a second late is not a business problem."
Durability, Once a write is committed, it persists through failure. ACID databases guarantee durability via write-ahead logging and synchronous disk writes. In interviews, pair durability with RPO: "For this payment system, RPO = 0, synchronous replication to two nodes before acknowledging."
Latency, Time from request send to response receive. Measured in milliseconds. Expressed as percentiles (p50, p95, p99). In interviews, distinguish between average and tail latency: "Our p50 is 10ms but our p99 is 200ms, that tells us we have occasional slow queries we need to investigate."
Throughput, Number of operations processed per unit time (QPS, RPS). Throughput bottlenecks appear at the weakest link in the system. In interviews, use throughput estimates to size components: "At 50,000 QPS peak, a single Postgres instance will not keep up, we need a read replica or caching."
SLA (Service Level Agreement), A contractual commitment to customers about system behavior. Includes remedies for violations. Always less strict than internal SLOs. Example: "Our SLA commits 99.9% availability to customers."
SLO (Service Level Objective), An internal target for a service level indicator. Drives engineering decisions. Stricter than the SLA to provide a buffer. Example: "Our internal SLO is 99.95% availability, giving us headroom above the 99.9% SLA."
SLI (Service Level Indicator), A quantitative metric that measures service behavior. Raw data that feeds SLOs. Examples: error rate, p99 latency, availability percentage. Example: "We measure three SLIs: error rate, p99 latency, and uptime percentage."
CAP Theorem, In a distributed system, you can guarantee at most two of: Consistency, Availability, Partition Tolerance. In practice, the choice is CP vs. AP since partitions are unavoidable. Example: "Cassandra is an AP system, it stays available during a partition but may return stale reads."
Partition Tolerance, The ability of a system to continue operating when network partitions prevent some nodes from communicating. Required for any genuinely distributed system. Example: "Because network partitions are unavoidable in a distributed system, we cannot sacrifice partition tolerance, the real choice is between CP and AP."
p99 Latency, The latency value below which 99% of requests complete. Your slowest 1% of users experience at most this latency. High p99 indicates tail latency problems, hot partitions, slow queries, GC pauses. Example: "Our p99 is 800ms, which tells us 1% of our users are hitting something slow, we need to identify the slow queries."
Summary
Non-functional requirements are not an afterthought, they are the primary inputs that shape your system design. Availability targets drive your redundancy strategy. Consistency requirements determine your database and replication choices. Durability requirements define your RPO and influence whether you use synchronous or asynchronous replication. Latency targets constrain your component choices by forcing you to keep the critical path fast. Throughput requirements drive your horizontal scaling and caching strategy.
In interviews, the candidates who score highest on NFRs are those who:
- Surface the requirements proactively, before drawing a single box
- Quantify the requirements (specific nines, specific ms targets, specific QPS)
- Connect each requirement to a specific component decision
- State the trade-off they are accepting when they choose one NFR property over another
The next lesson, Resource Estimation, takes the scale NFRs you surface here (DAU, QPS, storage) and shows you how to calculate the numbers that drive component sizing.
