Functional vs Non-Functional Requirements

What It Does vs How Well It Has to Do It

Functional vs Non-Functional Requirements

Functional requirements say what a system does; non-functional requirements say how well — and the non-functional ones are what actually shape the design.

7 min read Level 2/5 #system-design#requirements#scalability
What you'll learn
  • Separate functional from non-functional requirements
  • Name the core non-functional axes — scale, latency, availability, consistency, durability
  • See how the same feature yields different designs under different NFRs

Every design starts with two questions:

  • Functional requirementswhat does it do? The features. “Users can post a tweet.” “Users can follow other users.” “A timeline shows tweets from people you follow.”
  • Non-functional requirements (NFRs)how well must it do it? The qualities. “Timelines load in under 200ms.” “The service is available 99.99% of the time.” “We never lose a posted tweet.”

Beginners obsess over functional requirements because they’re the visible product. But the functional list for Twitter and for a toy clone is nearly identical — post, follow, view timeline. What makes Twitter hard is entirely non-functional: a million reads per second, sub-second timelines, near-perfect uptime. NFRs are what shape the architecture.

The core non-functional axes

AxisThe questionExample targets
ScaleHow much traffic and data?100M DAU, 1M reads/sec, 50TB/yr
LatencyHow fast per request?p99 < 200ms
AvailabilityHow much uptime?99.99% (“four nines”)
ConsistencyHow fresh/correct must reads be?Strong vs eventual
DurabilityCan we ever lose data?11 nines for stored objects
ReliabilityDoes it behave correctly under failure?No double-charges

These axes trade off against each other — you cannot max them all. The CAP theorem (later in this track) makes one such tradeoff formal: under a network partition, you choose consistency or availability, not both.

The same feature, different NFRs, different design

This is the whole point. Take one functional requirement — “send a message” — and change only the NFRs:

If the priority is…The design leans toward…
Lowest latency, OK to lose a messageIn-memory, fire-and-forget, no durable write
Never lose a messageDurable queue + acknowledgements + retries
Strict ordering per chatSingle partition per conversation
Global, billions of usersSharding, regional routing, eventual consistency

Same feature on the surface; four completely different systems underneath. The NFRs decided everything.

Where JavaScript engineers feel this

NFRs aren’t abstract — they show up directly in Node code:

An NFR decision, in Node script.js
// Functional requirement: "record that a user viewed a post."
// The NFR you pick changes the code completely.

// Priority = lowest latency, approximate counts OK:
//   fire-and-forget, don't await — the user's request returns instantly.
function recordView(postId) {
  queue.add('view', { postId });   // no await: ~0ms added latency
}

// Priority = exact counts, never lose a view:
//   durably write and confirm before responding.
async function recordViewExact(postId) {
  await db.increment('views', postId);   // adds latency, but durable
}
▶ Preview: console

The functional behavior is “count a view” in both cases. The non-functional requirement — fast-but-approximate vs slow-but-exact — is what dictates whether you await. That single choice ripples out into your whole architecture.

A quick checklist

For any prompt, before designing anything, fill in:

  • Functional: the 3–5 core operations (verbs the user performs).
  • Scale: DAU, read/write QPS, data volume per year.
  • Latency: the p99 target for the critical path.
  • Availability: how many nines.
  • Consistency: strong, or is eventual acceptable?
  • Durability: what must never be lost?

Nail these six and the architecture almost designs itself. The next lesson turns the “scale” line into actual numbers.