Fundamentals
Scaling
Vertical vs. horizontal, and which of compute, storage, or connections is actually your bottleneck.
"Scaling" gets used as a single word for a handful of distinct problems. Naming which one you're solving is most of the battle.
Vertical vs. horizontal
Vertical scaling — a bigger machine — is the right first move far more often than interview prep culture admits. It has no coordination cost and no new failure modes. It stops being the answer when you hit a ceiling (hardware limits, or a single point of failure you can no longer accept), not on day one.
Horizontal scaling — more machines — buys you headroom past that ceiling and resilience against losing one machine, at the cost of needing to coordinate state across them.
Instagram is a well-documented real example of this order: its main Postgres database ran vertically — on progressively bigger single boxes — for years before the team eventually sharded, specifically because vertical scaling had no coordination cost and horizontal scaling did. It's worth citing as evidence that horizontal scaling is a response to a specific, named ceiling, not the default correct answer.
type ScalingChoice = {
approach: "vertical" | "horizontal";
buys: string;
costs: string;
};
const dbScaleUp: ScalingChoice = {
approach: "vertical",
buys: "No coordination cost — a single Postgres primary going from 8 to 32 vCPUs can absorb several times more write throughput with zero application changes",
costs: "A hard ceiling once you hit the largest instance size available, and it stays a single point of failure until you add a replica",
};
Vertical
8 vCPU
32 vCPU
Ceiling
largest instance available
Horizontal
App instances (x3)
Load Balancer
distributes across them
Client
The three things that actually get scaled
- Compute — stateless request handling. Usually the easiest to scale horizontally, since a new instance needs no data to start serving traffic.
- Storage — where scaling gets hard, because data has to live somewhere and that somewhere has to stay consistent, or you've decided to accept it won't (see the next lesson).
- Connections — a proxy or load balancer sitting in front of both, routing traffic and hiding the fact that there's more than one of anything behind it.
Read-heavy vs. write-heavy
Most systems are read-heavy by a wide margin, which is why caching and read replicas dominate scaling discussions — they multiply read capacity without touching the harder problem of write throughput. A write-heavy system (an ingestion pipeline, a metrics collector) needs a different toolkit: partitioning writes across shards, buffering with a queue, and batching.
Say out loud, early, which side of that split the system you're designing falls on — it changes which of the next lessons' building blocks actually apply.