Back-of-the-Envelope Estimation for System Design

October 10, 2026 · 11 min read

"Design a URL shortener" means nothing until you know how big it is. One server and a SQLite file? A sharded cluster across three regions? Estimation is how you find out in two minutes, before drawing boxes. You're after the order of magnitude: 40 versus 4,000 versus 400,000 requests a second are three different designs. 38.6 versus 40 doesn't matter.

Numbers worth knowing

Time. A day is 86,400 seconds — call it 105. A month is about 2.6 × 106 seconds, a year about 3 × 107. So:

  • 1 million per day ≈ 12 per second
  • 100 million per day ≈ 1,200 per second
  • 1 billion per month ≈ 400 per second

Sizes. KB = 103, MB = 106, GB = 109, TB = 1012 bytes. A typical row with a few short strings is hundreds of bytes. A compressed photo is hundreds of KB. A minute of HD video is tens of MB.

Latency, roughly — each line is about an order of magnitude apart:

operationtime
read from main memory~100 ns
random read from an SSD~100 µs
round trip within a data centre~0.5 ms
disk seek (spinning disk)~5–10 ms
round trip between continents~150 ms

What one machine can do, very roughly: a simple cached read endpoint handles thousands to tens of thousands of requests a second; a single relational database, thousands of simple writes a second; a cache node, hundreds of thousands of operations a second. Real numbers depend heavily on the workload — treat these as a sanity check, not a promise.

A worked example

Assumptions, stated out loud: 100 million new short links a month; each link is read 100 times on average; records are about 500 bytes; keep five years.

const newLinksPerMonth = 100e6
const writesPerSec = newLinksPerMonth / (30 * 86_400)
const readsPerSec = writesPerSec * 100
const peakReadsPerSec = readsPerSec * 3
const bytesPerLink = 500
const storage5y = newLinksPerMonth * 12 * 5 * bytesPerLink
const cacheBytes = readsPerSec * 86_400 * 0.2 * bytesPerLink
const keySpace = 62 ** 7
estimate
month30 × 86,400 s ≈ 2.6M s
writes/s100M ÷ 2.6M ≈ 40

A URL shortener gets 100 million new links a month. A month is about 2.6 million seconds, so that is roughly 40 writes a second. Round freely — the goal is the order of magnitude.

0 / 4

Turn every number into a decision

An estimate is useful only if it changes the design. From the walkthrough:

  • 40 writes a second is nothing for one database. No write sharding is needed, and generating unique keys can be simple — a counter, or a random key with a collision check.
  • 12,000 reads a second at peak, mostly for popular links, says: put a cache in front, and serve redirects from the cache. Several stateless app servers behind a load balancer cover it with room to spare.
  • 3 TB over five years fits on one machine, but one machine is a single point of failure. Replicate for availability. Shard later, by key hash, if assumptions change — see sharding and replication.
  • 35 GB of hot data fits in memory on one cache node, or across a few.
  • 3.5 trillion possible 7-character keys against 6 billion needed means collisions are rare. Six characters (57 billion) would also work, but with less headroom.

Bandwidth is worth a line too: 4,000 reads a second × 500 bytes is 2 MB/s. Negligible — and saying so is part of the answer.

The full design built on these numbers is in the URL shortener case study.

Four more worked examples

The same method, on systems with very different shapes. Each one ends at the number that matters most — it's rarely the same one twice.

A chat app

50 million daily users, 40 messages each a day, 200 bytes a message.

  • Messages: 50M × 40 = 2 × 10⁹/day → ÷ 10⁵ = ~20,000/s, peak maybe 3×.
  • Storage: 2 × 10⁹ × 200 B = 400 GB/day → ~150 TB/year, ×3 for replication.
  • Connections: if 40% are online at peak, 20 million open sockets. At ~200,000 per gateway, that's about 100 gateways.

The number that matters: open connections. Message throughput is moderate; holding 20 million long-lived sockets is what shapes the architecture. See the chat system.

Photo sharing

10 million uploads a day, 2 MB each after compression, three resized copies adding another ~1 MB, 500 million feed views a day showing ~10 photos each.

  • Upload storage: 10⁷ × 3 MB = 30 TB/day → ~11 PB/year.
  • Upload bandwidth: 30 TB ÷ 10⁵ s = 300 MB/s inbound.
  • Image views: 5 × 10⁹/day → ~50,000/s; at ~200 KB a thumbnail-sized image, that's 10 GB/s outbound.

The number that matters: 10 GB/s out. No origin should serve that; it's a CDN problem. And petabytes a year means object storage with tiering — recent photos hot, old ones cold — not servers with disks.

Video streaming

1 million concurrent viewers at peak, average bitrate 5 Mbit/s.

  • Egress: 10⁶ × 5 Mbit/s = 5 Tbit/s.
  • Per edge server pushing ~40 Gbit/s: ~125 servers' worth of capacity, spread across many locations near viewers.

The number that matters: 5 Tbit/s is beyond any single data centre's comfortable egress, so the design is defined by edge caching and adaptive bitrate, not by the application servers at all.

A news feed

200 million daily users opening the feed 10 times a day; 50 million posts a day; 200 followers on average.

  • Reads: 2 × 10⁹/day → ~20,000/s.
  • Fan-out writes if you push each post to every follower: 50M × 200 = 10¹⁰/day → ~100,000/s.
  • Feed storage at 800 IDs × 8 bytes per user: 2 × 10⁸ × 6.4 KB ≈ 1.3 TB.

The number that matters: fan-out writes outnumber reads 5:1 — but each is tiny and asynchronous, which is why push still wins. The tail (accounts with millions of followers) is what breaks it; see the news feed.

From requests per second to servers

Once you have a peak rate, the server count is one division — if you know what one server can do. Two ways to estimate that:

From CPU time. If a request takes 5 ms of CPU, one core handles ~200 a second; a 16-core server, ~3,000. At 12,000 a second peak, that's 4 servers — plan 6–8 for headroom and failures.

From concurrency, with Little's law. The average number of requests in flight equals arrival rate × time each spends in the system:

in-flight = throughput × latency
12,000 req/s × 0.05 s = 600 concurrent requests

Little's law is the most useful formula in capacity planning because it connects three numbers you usually have two of. It tells you how many database connections you need (rate × query time — see connection pooling), how many worker threads, or how many messages sit in a queue.

Then add headroom. Run servers at 50–70% of measured capacity at peak, not 100% — latency climbs steeply as utilisation approaches 100%, because queues form. And add N+1 or N+2 so losing a machine (or a whole zone) doesn't overload the rest.

Storage, properly

Raw data size is the start of a storage estimate, not the end:

factortypical multiplierwhy
replication×3three copies for durability and availability
indexes×1.2–2every secondary index is another copy of some columns
overhead×1.1–1.5row headers, page fill factor, fragmentation
headroom×1.5never run disks above ~70% full
backups+1× or moredepends on retention and snapshot strategy

Multiply them together and 3 TB of "data" can mean 15–20 TB of provisioned disk. That's exactly the kind of gap that turns "fits on one machine" into "doesn't", so do the multiplication out loud.

Sizing a cache

"Put a cache in front" invites the next question: how big? Two inputs decide it.

The hot set. Traffic is rarely uniform — a small fraction of items gets most of the reads. A common working assumption is that ~20% of items get ~80% of traffic; for social content the skew is often far steeper. Cache the hot fraction of recent data, not all of it:

URL shortener: 40 new links/s × 86,400 s × 500 B ≈ 1.7 GB of new links a day
keep the last ~20 days hot → ~35 GB

The hit rate you need. Work backwards from what the database can take. If the database comfortably handles 2,000 reads a second and peak traffic is 12,000, the cache must absorb at least 10,000 — an 83% hit rate, with a margin on top. If your hot-set estimate can't plausibly deliver that, you need read replicas as well as a cache.

Then check the cache's own limits: ~35 GB fits one node's memory, and 12,000 operations a second is a small fraction of what one cache node can serve. One primary plus a replica, for availability rather than capacity.

Estimating queues

For anything asynchronous — fan-out, emails, video transcoding — the question is whether workers keep up, and how far behind they fall in a burst.

  • Steady state: workers must process faster than jobs arrive, with margin. If each job takes 200 ms and 600 arrive a second, you need at least 600 × 0.2 = 120 concurrent workers — Little's law again.
  • Bursts: if a campaign enqueues 10 million jobs and workers drain 2,000 a second, the backlog takes 5,000 seconds — about 80 minutes. Is that acceptable for this job type? If not, add workers, or prioritise so urgent jobs skip the line.
  • Queue storage: 10 million jobs × 1 KB = 10 GB sitting in the broker. Fine for a log like Kafka; worth checking for an in-memory broker.

An interview script

In an interview, estimation should take two or three minutes and leave a small table on the whiteboard that the rest of the design refers back to. A shape that works:

  1. Ask or state the scale: daily active users, actions per user per day, read/write ratio, object sizes, retention. Write them down.
  2. Compute writes per second and reads per second, average and peak.
  3. Compute storage for the retention period, then mention the multipliers.
  4. Compute bandwidth if large objects are involved; skip it with one sentence if they aren't.
  5. Say what each number implies: "40 writes a second — one database"; "12,000 reads a second — cache plus a few app servers"; "10 GB/s out — this is a CDN design".

Then move on. Returning to the table later ("we said 35 GB hot, so one cache node") is what makes the estimates look like engineering rather than ritual.

Common mistakes

  • Mixing bits and bytes. Network speeds are in bits (Gbit/s), storage in bytes. A 1 Gbit/s link moves ~125 MB/s, not 1 GB/s. A factor of 8 is enough to change a design.
  • Using daily averages for capacity. Traffic follows people's days: peak hours can be 3× the average, and launches or live events 10× or more.
  • Ignoring the read/write ratio. "1,000 requests a second" hides whether that's 990 reads or 990 writes — two completely different systems.
  • Forgetting the fan-out. One user action often becomes many internal requests: a page view might call ten services, and a post might write to a thousand feeds. Estimate the internal rate, not just the external one.
  • False precision. "We need 37.4 servers" sounds rigorous and isn't. "Tens of servers" is the honest answer, and it's enough to decide.

Habits that keep it honest

  • State assumptions before computing, and write them where the interviewer (or your team) can see them. Wrong assumptions are easy to fix if they're visible.
  • Round aggressively. 86,400 → 105, 2.6M → 3M. Keep one significant figure, multiply in powers of ten.
  • Average, then peak. Size for peak (2–10× the average, depending on how spiky traffic is) and storage for growth.
  • Separate reads from writes. They usually differ by orders of magnitude and lead to different decisions: caching and replicas for reads, partitioning and queues for writes.
  • Watch for the multiplier you forgot: replication factor (×3), indexes, metadata, backups, logs. Storage estimates are often low by several times.
  • Sanity-check against something known. If your estimate says a chat app for a small company needs 500 servers, an assumption is wrong.

Numbers age; ratios don't

Hardware keeps getting faster, so specific figures — requests per core, cache-node throughput, SSD latency — drift over the years. The ratios between them hold up much better: memory is roughly a thousand times faster than an SSD read, which is far faster than a network round trip, which is far faster than crossing an ocean. Designs are decided by those ratios. When a precise number matters, measure it on your own hardware with your own workload, and use the estimate only to decide what's worth measuring.

Try it

The capacity calculator does this arithmetic from a few inputs. Use it to check your mental maths, not to replace it — in an interview, what matters is the reasoning from each number to a decision.