The verdict
Scale reads first with read replicas — it's the cheapest, least invasive step. Split tables by feature (functional/vertical partitioning) when different parts of the schema have very different load. Reach for sharding — horizontal partitioning across nodes — only when a single primary genuinely can't handle the write volume or dataset size. Sharding is powerful but adds cross-shard queries, rebalancing, and hot-shard risk, so exhaust caching, indexing, and replicas before you shard.
How to decide
- 1Are you read-bound or write-bound? Most systems hit read limits first.
- 2Have you already added caching, proper indexes, and read replicas?
- 3Is a single primary's write throughput or storage the real ceiling?
- 4Can you choose a shard key that spreads load evenly and avoids cross-shard queries?
- 5Shard last. It's the highest-complexity, hardest-to-reverse step.
The options
Read replicas
Copies of the primary that serve read traffic.
Best for
- Read-heavy workloads
- The first scaling step for most databases
- Offloading analytics/reporting from the primary
Strengths
- Simple to add; scales reads horizontally
- No application changes for most read paths
- Also improves read availability
Weaknesses
- Doesn't scale writes at all — one primary
- Replication lag = eventual consistency on reads
- Read-your-writes needs routing care
Vertical / functional partitioning
Split the schema by feature into separate databases.
Best for
- Distinct feature areas with different load
- Isolating a hot table set
- A step before full sharding
Strengths
- Reduces load on any single database
- Clear ownership boundaries
- Less complex than horizontal sharding
Weaknesses
- Cross-feature joins/transactions get harder
- Eventually a single feature's DB can still be the bottleneck
Sharding (horizontal partitioning)
Split rows across nodes by a shard key.
Best for
- Write volume or dataset beyond one primary
- Very large tables with a natural partition key
- Linear write scale requirements
Strengths
- Scales writes and storage horizontally
- Each shard is smaller and faster
Weaknesses
- Cross-shard queries and transactions are hard
- Bad shard key → hot shards and skew
- Rebalancing/resharding is operationally painful
Trade-offs at a glance
| Dimension | Read replicas | Vertical / functional partitioning | Sharding (horizontal partitioning) |
|---|---|---|---|
| Scales | Reads | Reads + isolates writes | Reads + writes + storage |
| Complexity | Low | Medium | High |
| Cross-node queries | N/A | Harder | Hard |
| Consistency | Lag on replicas | Per-DB strong | Per-shard strong |
| Rebalancing | None | Rare | Painful |
| Use when | Read-bound | Distinct hot features | Write/storage-bound |
In the interview
In the scaling/bottleneck phase of a design — 'the database is the bottleneck, what now?' The interviewer wants to see you scale in the right order, not jump straight to sharding.
What a Staff answer includes
A Staff answer scales reads before writes, exhausts caching/indexing/replicas first, and only shards when writes or storage force it — choosing a shard key deliberately and naming the hot-shard, cross-shard-join, and rebalancing problems up front.
Follow-ups you should expect
- →What shard key would you choose, and how do you avoid hot shards?
- →How do you run a query that spans shards?
- →What consistency do reads from a replica give you?
- →How do you reshard when a shard gets too big?
Common mistakes
- ✕Sharding prematurely, before caching, indexing, and replicas.
- ✕A bad shard key that creates hot shards and skew.
- ✕Forgetting replication lag means eventual consistency on replica reads.
- ✕Treating sharding as easy to change later — it isn't.
Further reading
Related decisions
SQL vs NoSQL
Default to relational (Postgres). Reach for NoSQL only when a specific access pattern or scale requirement makes relational a poor fit.
Strong vs Eventual Consistency
Strong consistency when correctness needs every reader to see the latest write (money, inventory, uniqueness); eventual when availability and scale matter more and brief staleness is tolerable (feeds, counts, caches).