Module 2: Napkin Estimation (Back-of-the-Envelope)
1. Module introduction: the napkin before the server
Description
In module 1 you learned the four-step framework for approaching any open design problem: first you clarify the requirements, then you estimate the scale, then you draw the high-level design, and finally you deep-dive into the parts that deserve it. You also met Enlace, the URL shortener that will accompany you throughout the guide: it takes a long URL, returns a short one like enla.ce/aX9kR2q, and on visiting it redirects to the original. In that module the second step —estimation— flew by: we said "100 million URLs a month is about 40 writes per second" and moved on. This module grabs that step, opens it fully, and teaches you to do it yourself.
The skill is called back-of-the-envelope estimation: literally, the calculations that fit on the back of an envelope or a coffee napkin. The idea is to produce, in five minutes and with grade-school arithmetic, the four numbers that govern a design: how many requests per second it handles (QPS), how much disk it needs over several years, how much bandwidth it moves, and how much memory is needed for a cache to be worth it. These aren't exact numbers —nobody wants them exact on an interview whiteboard or in the first version of a design— but numbers of the correct order of magnitude. And that, however modest it sounds, is what decides the design: the difference between "this fits in one server" and "this needs a hundred servers" is resolved with these calculations, not with intuition.
Connection to the module: this is the map-lesson. We don't calculate in depth yet; here we build the motivation (why you estimate before designing), the vocabulary (QPS, working set, order of magnitude), and the inventory of the four numbers you'll produce for Enlace, so the rest of the module doesn't have to explain them. Lesson 2 gives you the tools (powers of 10, seconds per day, units). Lessons 3 to 6 are the heart: one for each number —QPS, storage, bandwidth, memory—. Lesson 7 teaches you the discipline that makes an estimate defensible: smart rounding and sanity checks. Lesson 8 puts it all together in Enlace's complete capacity table. The whole module estimates the same system with the same anchor numbers, so your attention is on the method, not the prompt.
The banquet count: why you estimate before you cook
Imagine you're put in charge of a wedding's catering and the only thing you know is "300 guests are coming". You haven't chosen the menu yet, you haven't booked the hall, you haven't hired waiters. And yet, with that single fact you can already calculate almost everything that matters to decide whether the plan is realistic: 300 people eat about 300 main courses, plus say 1.5 drinks per person per hour over 4 hours is about 1,800 drinks, and at one waiter per 20 diners you need about 15 waiters. None of those numbers is exact —maybe someone doesn't drink, maybe they get seconds— but they're all the right size, and with them you already know it does not fit in your living room, that you do need a large drinks supplier, and that a single waiter is madness. You ruled out the impossible plans before spending a peso.
That's the back-of-the-envelope math, and notice three things about the wedding count that hold for any system:
- One scale figure rules over everything else. "300 guests" was enough to size food, drink, and staff. In Enlace, "100 million URLs a month" will be enough to size servers, disk, network, and memory. Find the scale number and almost everything derives from it.
- The order of magnitude is what decides. Whether it's 15 waiters or 18 doesn't change the plan; whether it's 15 and not 1, or 15 and not 150, changes it completely. You seek the correct power of 10, not the decimal.
- Estimating is cheap and getting the design wrong is expensive. The wedding count takes two minutes; hiring the wrong hall costs the wedding. In systems it's the same: two minutes of napkin math save you weeks of building something that can't handle the load or spends a hundred times more than needed.
An engineer who doesn't estimate is a cook who buys the food and then counts the guests. That's why estimation is step 2 of the framework, right after clarifying the requirements and before drawing a single box: the numbers decide which design even makes sense to draw.
The four numbers you'll produce for Enlace
The whole module aims for you to be able to fill in, from memory and in five minutes, this table for Enlace. Here it is complete as a destination; each lesson builds one row, and in lesson 8 you assemble it from scratch.
| Number | What it answers | Value for Enlace | Lesson |
|---|---|---|---|
| QPS (queries per second) | How many requests per second? | ~40 writes/s, ~4,000 reads/s | 3 |
| Storage | How much disk at 5 years? | ~6 TB | 4 |
| Bandwidth | How many bytes/s in and out? | ~20 KB/s write, ~2 MB/s read | 5 |
| Memory (working set) | How much RAM does the cache need? | ~333 MB (hundreds of MB) | 6 |
Four numbers. With them you already know a great deal about Enlace before designing it: that the write is child's play (40/s any single server does with one hand tied), that the read is 100 times more intense (4,000/s already calls for thinking about caching and replicas), that the disk grows to about 6 TB (fits on a few disks but must be planned), that the bandwidth is tiny (2 MB/s is nobody's bottleneck), and that the hot part of the data fits comfortably in one server's RAM (which is why caching will work). All that, from four calculations.
The complete flow of the module looks like this: from a handful of scale figures come the four numbers, and from the four numbers come the design decisions you'll make in the following modules.
flowchart LR
subgraph Input["Anchor numbers (the prompt)"]
A1["100M URLs/month"]
A2["100:1 ratio"]
A3["5-year retention"]
A4["~1 KB record"]
end
subgraph Numbers["The 4 capacity numbers"]
N1["QPS<br/>~40 w/s, ~4000 r/s"]
N2["Storage<br/>~6 TB"]
N3["Bandwidth<br/>~20 KB/s, ~2 MB/s"]
N4["Memory<br/>~333 MB"]
end
subgraph Decisions["Design decisions (M3-M7)"]
D1["cache? replicas?"]
D2["sharding?"]
D3["bottleneck?"]
end
A1 --> N1
A2 --> N1
A1 --> N2
A3 --> N2
A4 --> N2
N1 --> N3
A4 --> N3
N1 --> N4
N1 --> D1
N2 --> D2
N3 --> D3
N4 --> D1
Read it left to right: the scale figures (column 1) feed the capacity numbers (column 2), and those numbers justify the design decisions (column 3). Note that no number comes from nowhere: each arrow is a calculation you'll learn to do. And note that the numbers chain together —the QPS feeds bandwidth and memory— so the order of the lessons is no accident.
The four numbers, one by one, and the decision each triggers
It's worth looking at each number not as an isolated fact but as the trigger of an architecture decision. That's the reason estimation exists: not to collect figures, but to know what to build.
QPS — decides whether you need to scale and where. Requests per second is the most-used number in the whole discipline, because it sets the system's rhythm. For Enlace there are two: ~40 writes/s and ~4,000 reads/s. The write, at 40/s, asks for nothing special: a single database is plenty. The read, at 4,000/s and with the promise that it'll grow, is the one that sends the design toward a cache (module 4) and toward read replicas (module 5). All of Enlace's character —a read-heavy system— is in the 100:1 gap between those two numbers, and that gap is revealed by the QPS.
Storage — decides whether one disk is enough or you need to spread. How much disk at 5 years answers a binary design question: does everything fit on one machine or do you have to shard? For Enlace it's ~6 TB. That fits on a few disks of a single modern server, so Enlace is not obligated to shard for space —an important piece of news, because sharding is expensive in complexity—. But 6 TB "fits tight and growing", so it's a number to watch. Module 5 decides what to do with it; this module only produces it.
Bandwidth — decides whether the network is the bottleneck. The bytes per second in and out tell you whether the network link holds up. For Enlace the answer is a relief: ~20 KB/s in and ~2 MB/s out are ridiculously small amounts for any modern network (a house with fiber moves more). The design conclusion is "the network isn't Enlace's problem", and that's valuable: it tells you where not to spend effort. In a video or photo service, this same number would be enormous and would change the whole design; comparing both cases (lesson 5) teaches you to read what kind of system you have on your hands.
Memory — decides whether caching is worth it. How much RAM the hot part of the data asks for —the working set— answers whether a cache makes economic sense. For Enlace, the 20% of hot URLs of a day weighs about ~333 MB: hundreds of megabytes that fit easily in the RAM of a single cache server. That number is the arithmetic justification of all of module 4: since the working set (hundreds of MB) is tiny against the total disk (6 TB), caching the hot part in memory is cheap and eliminates almost all reads to disk. Without this calculation, "let's add a cache" would be an act of faith; with it, it's a decision with a number.
Notice the pattern: each number doesn't end in itself, it ends in a decision. A mature estimator doesn't say "the read QPS is 4,000"; they say "the read QPS is 4,000, so I need a cache and replicas". The number is the means; the decision is the end.
Enlace's anchor numbers
These are the input figures, fixed for the whole guide. Memorize them: they're the problem statement.
- 100 million new URLs per month.
- read:write ratio = 100:1 (people visit far more than they create).
- Retention: 5 years. Average long URL: 500 bytes; complete record: ~1 KB.
- 7-character base62 codes (the namespace; the why is module 3's).
From those four inputs come the four capacity numbers. The whole art of the module is the conversion.
Worked example: the first number, writes per second
Let's do one of the four calculations right now, in full, so you see what the module is about. Let's go for the simplest: how many writes per second does Enlace generate? The input figure is "100 million new URLs per month". A new URL is a write (a shorten). So the question is: 100 million events spread across a month, how many per second?
The only trick is converting "a month" to seconds. A month has about 30 days, each day 24 hours, each hour 3,600 seconds:
seconds per month = 30 days × 24 hours × 3,600 s = 2,592,000 s
And then:
qps_write = 100,000,000 writes / 2,592,000 s
Don't do it from memory: run it. This is a Python script you can paste as-is into your terminal (python3).
# Enlace's writes per second, computed, not quoted.
writes_per_month = 100_000_000 # 100M new URLs / month
seconds_per_month = 30 * 24 * 3600 # days * hours * seconds
qps_write = writes_per_month / seconds_per_month
print(f"seconds per month = {seconds_per_month:,}")
print(f"qps_write = {qps_write:.2f} writes/s")
What to expect. When you run it you see this:
seconds per month = 2,592,000
qps_write = 38.58 writes/s
The raw result is 38.58 writes per second. And here appears the module's first lesson of style: nobody says "38.58". A napkin number is rounded to something the mind can hold and that communicates the order of magnitude without faking a precision you don't have. 38.58 rounds to ~40 writes per second. It's not "more or less", it's more honest: you don't know whether it'll be exactly 100M a month (and in December, with more traffic?), so reporting 38.58 would be false precision. ~40/s tells the truth: "on the order of a few tens per second".
With that number you've already made your first design decision without drawing anything: 40 writes per second is a trivial load. A single modest database does thousands of inserts per second. So Enlace's write isn't the problem. The problem, you already sense, is going to be the read —100 times more—, and that's what lesson 3 develops.
And so you see how the numbers chain together, let's follow one more step with no new data. The read:write ratio is 100:1, so the second number comes from the first with a multiplication:
qps_read = qps_write * 100 # read:write ratio = 100:1
print(f"qps_read = {qps_read:.0f} reads/s -> ~4,000/s")
qps_read = 3858 reads/s -> ~4,000/s
Without touching the original prompt, just by multiplying by 100, you already have the number that will govern Enlace's design: ~4,000 reads per second. That jump of two orders of magnitude between writing (40/s) and reading (4,000/s) is the signature of a read-heavy system, and it's the reason modules 4 and 5 —cache and read replicas— exist. Notice what just happened: with a division, a multiplication, and two roundings you went from a vague prompt to two architecture conclusions ("the write isn't the bottleneck; the read is, and by a factor of 100"). That's the whole module, repeated four times.
What makes a number "defensible"
The module's keyword is defensible. A defensible number isn't an exact number; it's a number you can justify out loud as you write it. When you say "~40 writes per second", you have to be able to say in the same breath: "because it's 100 million a month, a month is about 2.6 million seconds, and 100 over 2.6 gives about 40". If you can walk the path back, the number is defensible. If you pulled it from memory or an intuition, it isn't —even if it's right.
This has three practical consequences that govern the whole module:
You show the path, not just the result. A loose ~40/s is worth nothing; 100M / 2.6M s ≈ 40/s is worth everything, because anyone can follow and verify it. In each lesson you'll write the complete calculation, not just the answer.
You round from the start, not at the end. Since the numbers are approximate to begin with, dragging decimals is theater. "A month is ~2.6 million seconds" is better than "2,592,000" for the mental calculation, and the result comes out just as good. Lesson 7 turns this into a discipline.
You state the assumption. "100M a month" assumes a 30-day month and even traffic. If someone asks "and the peak?", the honest answer is "I assumed average; the peak can be 2 or 3 times more, about 100-120 writes/s". A good estimator knows what they assumed and says it before being asked. Lesson 3 introduces the peak factor precisely for this.
A number you can justify, rounded with judgment, and whose assumptions you state: that's defensible. And a design made of defensible numbers is a design that withstands questions.
The order of magnitude: the only precision you need
The whole module rests on an idea worth understanding well from now: in systems estimation, what matters is the order of magnitude, that is, the power of 10 a number belongs to, not its digits. "40 writes per second" and "60 writes per second" are, for design purposes, the same number: both are "tens per second", both a single database does without sweating. What would change the design is jumping from "tens" to "thousands" or to "millions" —from 10¹ to 10³ to 10⁶—, because each jump of three zeros usually means a new piece of architecture.
Think of it like a graduated ruler where the marks aren't 1, 2, 3 but 10, 100, 1,000, 10,000. When you estimate, your only job is to place the number on the correct mark. Whether within the "thousands" mark the real number is 4,000 or 7,000 almost never changes the decision; whether it's in "thousands" and not "millions", always. That's why a 50% error in a napkin estimate is usually harmless (you're still on the same mark), while an error by a factor of 100 is fatal (you moved marks and designed for the wrong system).
This is liberating, because it makes the arithmetic easy. You don't need a calculator or to fuss over decimals: you need to count zeros. "100 million" is 10⁸. "A month in seconds" is on the order of 10⁶ (2.6 million). 10⁸ divided by 10⁶ is 10², that is, on the order of 100 —and the fine number turns out to be 40, within that mark—. Learning to count zeros instead of multiplying digits is half the module's skill, and lesson 2 sharpens it with powers of 10.
A warning so you don't overdo it in the other direction: "order of magnitude" isn't an excuse for total laziness. There's a real difference between 40/s and 4,000/s —a factor of 100, two marks— and confusing them would be a disaster. The discipline is: round aggressively within a mark, but never get the mark wrong. Counting zeros carefully is exactly what avoids the mark error.
The napkin's limits: when it's not enough
Back-of-the-envelope estimation is powerful precisely because it's fast and approximate, but those same virtues are its limits, and a good engineer knows where the napkin ends and another tool begins.
The napkin sizes; it doesn't measure. An estimate tells you the expected size of the problem before building anything. It doesn't replace measuring the real system once it exists: the true latency, the QPS that actually arrives, the real record size. The napkin is for deciding what to build; measurement (metrics, profiling, load tests) is for verifying that what you built behaves as you expected. Both are needed, in that order. Designing without estimating is reckless; but believing that estimation replaces measurement in production is just as dangerous.
The napkin assumes a regime; the jumps break it. Our calculations assume reasonably even traffic and smooth growth. They don't capture a viral event (a URL that suddenly gets a million visits in an hour) or a sudden scale change (going from 100M to 10,000M users because the product exploded). Those cases exist and are designed separately, with margins and defense mechanisms. The napkin gives you the base case on which you then reason about the extremes —not the extremes themselves—.
The napkin doesn't choose between similar designs. It works wonderfully to rule out the impossible ("this doesn't fit in a server") and confirm the roomy ("this is plenty for a server"). But when two viable designs are close —one more replica or a bigger cache?, shard now or in a year?— the decision is no longer arithmetic but a matter of tradeoffs (cost, complexity, risk), and that lives in other guides of the ecosystem (decisions and tradeoffs, resilience patterns). The napkin takes you to the door of those decisions; it doesn't make them for you.
In short: the napkin is the first filter, very fast and cheap, that tells you the size of the problem and rules out the absurd plans. It's enormous for what it does and honest about what it doesn't do. This module teaches you to use it well and to know when to pass the baton to the next tool.
Common mistakes
Skipping the estimation and "designing just in case" (over-engineering). What happens: someone reads "URL shortener", imagines millions of users, and jumps straight to a design with twenty microservices, message queues, and global sharding, without having computed a single number. Why it happens: without estimating, the fear of falling short pushes you to design for the largest imaginable scale. How to detect it: if your design has pieces you can't justify with a number ("why sharding?" "in case it grows"), you're designing out of fear, not data. How to fix it: estimate first. When you see that the write is 40/s and the disk 6 TB, most of those pieces fall away on their own, because no number asks for them. Estimation is the best vaccine against over-engineering.
Confusing precise with exact (false precision). What happens: the person reports "38.58 writes per second" or "6.144 TB" and feels rigorous for the decimals. Why it happens: in school, more decimals meant a higher grade; here it's the reverse. How to detect it: if your estimate has three significant figures when the input ("100M a month") has one, you invented precision. How to fix it: round to one significant figure (~40/s, ~6 TB). A rounded number communicates honestly how much you know; a precise decimal lies by saying you know more than you do. Lesson 7 formalizes it.
Estimating from memory instead of computing (a dangerous shortcut). What happens: someone recalls that "a URL shortener is like 4,000 reads per second" and drops it without the calculation. Why it happens: the anchor numbers of famous cases circulate as folklore and it's a hassle to derive them. How to detect it: if you're asked "where do the 4,000 come from?" and your answer is "it's the typical number" instead of the arithmetic path, you quoted it, you didn't compute it. How to fix it: always reconstruct the calculation. The value of the napkin isn't getting the number right —it's being able to derive it in front of whoever asks, with different data if the prompt changes. A quoted number doesn't survive "and if it were 500 million a month?"; a computed one does.
Exercises
Exercise 1 — The scale figure rules. Of Enlace's four anchor numbers (100M URLs/month, 100:1 ratio, 5-year retention, 7-char code), say which one you'd use as the starting point for each of these three capacity numbers, and why: (a) the write QPS; (b) the read QPS; (c) the storage at 5 years.
See solution
- (a) Write QPS starts from 100M URLs/month. A new URL is a write, so you just spread 100M across the seconds of a month:
100M / 2.59M s ≈ 40/s. - (b) Read QPS starts from the write QPS and the 100:1 ratio. You don't need new data: if there are 40 writes/s and it's read 100 times per write, that's
40 × 100 = 4,000reads/s. This is an important pattern: the numbers chain together, one feeds the next. - (c) Storage starts from 100M/month, the 5-year retention, and the record size (~1 KB). You need all three: how many records per month, for how many months, and how much each weighs.
100M × 12 × 5 × 1 KB.
The moral: almost everything derives from the main scale figure (100M/month), sometimes directly and sometimes chaining with another number you already computed (like the read QPS, which comes from the write one).
Exercise 2 — Round with judgment. These are three raw napkin calculations. Rewrite each result as you'd report it on a whiteboard, with one significant figure, and say in one sentence what the rounded number communicates. (a) 38.58 writes/s; (b) 6.144 TB; (c) 1,929,012 bytes/s of read.
See solution
- (a)
38.58/s→ ~40 writes/s. It communicates: "on the order of a few tens per second, a trivial load for a single database". - (b)
6.144 TB→ ~6 TB. It communicates: "on the order of a few terabytes; fits on some disks but the growth must be planned". - (c)
1,929,012 bytes/s→ ~2 MB/s. First it's best to go from bytes to a readable unit (1,929,012 B/s ≈ 1.93 MB/s) and then round to ~2 MB/s. It communicates: "tiny bandwidth; the network isn't the bottleneck".
In all three cases, the rounded number reads at a glance and communicates a design conclusion. The raw number, with all its digits, hides the conclusion behind false precision. Rounding isn't losing information: it's revealing the part that matters.
Exercise 3 — State the assumption. When you say "Enlace does ~40 writes per second", you're assuming several things for the calculation to work. Name at least two assumptions hidden in that number, and for each say how the result would change if the assumption were false.
See solution
At least these two (there are more):
- Assumption: the traffic is even (average, not peak). The calculation spreads 100M across all the seconds of the month equally, as if at 3 a.m. as many URLs arrived as at noon. In reality traffic has peaks. If the peak is 3 times the average, at peak hour it's not 40/s but ~120/s. The system has to be sized for the peak, not the average, so this assumption can make you underestimate by a factor of 2-3. (Lesson 3 covers it.)
- Assumption: the month has 30 days and the pace is constant all year. We used 30 days to get "round" seconds. A 31-day or 28-day month changes the denominator a bit, but since we seek the order of magnitude, it doesn't matter. More relevant: we assume 100M every month; if the service grows, in two years it could be 200M/month and the number doubles.
What matters isn't the exact list, but the habit: a napkin number comes with assumptions, and whoever states it should know them. "~40/s assuming average traffic; at peak, 2-3x more" is a defensible answer. "~40/s" on its own, without knowing what you assumed, falls apart at the first follow-up.
From module 1's "single box" to the numbers
In module 1 you drew Enlace as a single box: a service that receives shorten and resolve, with a database attached. It was the simplest possible high-level design, and on purpose it had no cache, no replicas, no load balancer. The natural question is: why not leave it like that? The answer is given by this module's numbers, and that's why estimation goes right between "the one-box design" and "the scaled design".
Look at it as a dialogue between the design and the numbers. The single box says: "I can handle the writes" —and the write QPS (~40/s) proves it right: a single database is plenty for that, so the write stays in the box—. But the box also says "I can handle the reads", and there the read QPS (~4,000/s, growing) starts to raise an eyebrow: a single database can handle 4,000 reads/s today, but it's fragile, and each read hits the disk. The memory number seals the argument: since the hot part fits in ~333 MB of RAM, putting a cache in front is cheap and removes almost all those reads from disk. And the storage number (~6 TB) whispers in its ear: "for now I fit on one disk, but keep an eye on me".
So, without having drawn the cache or the replicas yet, the four numbers already tell you what's going to happen to the single box when the system grows: the write stays, the read is protected with cache and replicas, the disk is watched and maybe spread. Modules 4 to 7 execute that plan. But the plan is dictated by the numbers, and the numbers you produce here. Estimating isn't a formality between two design modules: it's the bridge that turns the naive box of module 1 into a system with judgment.
Summary and next step
In this lesson you saw why you estimate before designing: a single scale figure (100M URLs/month) governs almost all the decisions, the order of magnitude is what decides the design, and estimating is so cheap that getting it wrong for not doing it is unforgivable. You met the four numbers you'll produce for Enlace —QPS, storage, bandwidth, memory— and their destination values (~40 and ~4,000/s, ~6 TB, ~20 KB/s and ~2 MB/s, ~333 MB), along with the input anchor numbers that generate them. And you computed the first one for real, in Python: 100M/month ÷ 2.59M s/month = 38.58, reported as ~40 writes/s.
Above all, you learned what makes a number defensible: that you can justify its path out loud, that it's rounded with judgment from the start, and that you state the assumptions holding it up. A design made of defensible numbers withstands questions; one made of intuitions doesn't.
Before moving on you should be able to: explain why you estimate before drawing; name the four capacity numbers and what question each answers; convert a raw result (38.58/s) into a reportable one (~40/s) and say what it communicates; and state at least one hidden assumption in an estimate.
What comes next is sharpening the tools. Before computing the other three numbers you need to handle with ease the powers of 10, the magic number of seconds per day (~86,400), and the units (KB/MB/GB/TB, with their base-1000-vs-1024 trap). Lesson 2 is that toolkit: short, practical, and the foundation of everything that follows.
Resources
- Martin Kleppmann, Designing Data-Intensive Applications (O'Reilly, 2017), Chapter 1 — dataintensive.net. The first chapter defines reliability, scalability, and maintainability, and introduces the way of thinking about workloads (percentiles, throughput) that underpins all estimation. It's the guide's bedside book; in English.
- The System Design Primer — github.com/donnemartin/system-design-primer. The "Back-of-the-envelope calculations" section lists exactly this module's kit (powers of 2, latencies, time conversions). It's free and in English; we'll reconstruct it step by step.
- Jeff Dean, "Numbers Everyone Should Know" / "Latency Numbers Every Programmer Should Know" — living compilation at gist.github.com/jboner/2841832. The reference latency table (memory vs disk vs network) we'll use in lesson 7 for the sanity checks. Orders of magnitude, not exact values.