# Back-Of-The-Envelope Capacity Planning
Capacity planning turns product requirements into rough load, storage, bandwidth, and cost numbers. The goal is not exact prediction. The goal is to catch designs that are obviously impossible or overbuilt.
## When To Use It
Use it before choosing storage, caches, queues, shard counts, or vendor limits. A quick estimate should say which resource is likely to dominate and which part of the design needs protection first.
Good estimates connect directly to [[wiki/non-functional-requirements]]. If the system needs 99.9% availability and low p99 latency, peak load, retry behavior, and failure capacity matter more than neat average numbers.
## Core Inputs
| Input | Example |
|---|---|
| Users | DAU, MAU, peak concurrent users. |
| Traffic | reads/sec, writes/sec, fanout, peak multiplier. |
| Data size | item size, retention, replication factor. |
| Latency | p50/p95/p99 targets by operation. |
| Growth | monthly growth, event spikes, seasonal peaks. |
| Cost | compute, storage, egress, observability, vendor pricing. |
Also note the shape of the workload. A million small writes stress indexes and coordination differently from a few large uploads. A read-heavy product may be limited by cache memory, while a media product may be limited by egress.
## Fast Method
1. Estimate active users and peak factor.
2. Convert actions per user into QPS.
3. Split reads, writes, background jobs, and fanout.
4. Estimate bytes per write and retention.
5. Apply replication, indexes, caches, and derived data multipliers.
6. Check bottlenecks: database writes, queue lag, cache memory, egress, CPU, or provider quotas.
7. Add margin, then revisit the numbers after real telemetry exists.
## Worked Example
If 10 million DAU each generate 20 feed reads/day:
- daily feed reads: 200 million,
- average QPS: about 2,300,
- peak at 10x: about 23,000 QPS.
That number decides whether one database query per feed item is absurd, whether caching is mandatory, and whether the ranking path needs strict latency budgets. If each feed read loads 30 items and each item does a profile lookup, the naive internal read load is much larger than the external QPS.
Now estimate writes. If users create 2 million posts/day, average write QPS is about 23 and peak may be 230. That sounds small until fanout appears. Fanning out each post to 500 followers synchronously turns 230 writes/sec into 115,000 delivery records/sec.
That estimate argues for async fanout, bounded workers, idempotent delivery, and queue depth alarms. It may also suggest a hybrid feed model: fanout for normal accounts and pull-on-read for very large accounts.
Storage needs the same multiplier thinking. At 2 KB/post, 2 million posts/day is about 4 GB/day raw. Replication, secondary indexes, search copies, analytics exports, and backups can easily turn that into many times more.
## Decision Checks
| Estimate Says | Likely Design Move |
|---|---|
| Reads dominate | Add cache, CDN, read replicas, or precomputation. |
| Writes dominate | Choose partition keys, batch work, and avoid hot rows. |
| Fanout dominates | Use queues, async workers, and retry limits. |
| Egress dominates | Compress, resize, cache near users, and price bandwidth. |
| Tail latency is tight | Keep the hot path small and move work offline. |
## Common Mistakes
- Designing for average QPS and forgetting peak traffic.
- Counting user requests but not internal service calls.
- Ignoring index, replication, backup, and derived-data overhead.
- Treating retries as free during dependency failures.
- Mixing online request work with background work.
- Forgetting provider quotas, connection limits, and egress cost.
## Senior Judgment
The right estimate is usually a range. Say "peak reads are probably 20k to 50k QPS" instead of pretending "23,148 QPS" is real. Design choices should survive the range, and the riskiest number should get measured first.