On this page

Sharding and Shard Keys

What Sharding Is

Sharding means splitting your data across several database servers, so no single server holds everything. Each piece is a shard: a standalone database with its own CPU, memory, and disk, holding only part of the data. Together, the shards hold the full dataset.

Think of a library that outgrew its building. Instead of one giant building, you open branches, and each branch keeps only some of the books. Each branch is smaller, and visitors are spread across them.

1Before After (sharded by user_id)
2App → [ one DB: all orders ] App → Router ─┬→ [ Shard 1: some users' orders ]
3 ├→ [ Shard 2: some users' orders ]
4 └→ [ Shard 3: some users' orders ]

Replication copies the same data to more servers, which scales reads. Sharding splits the data, which scales writes and storage. Each shard is usually also a small replica set, so it has failover too.

Do You Even Need It?

Sharding comes last, after a bigger server, good indexes, caching, and read replicas. Justify it with numbers:

1Orders: 5 million/day × 1 KB = 5 GB/day ≈ 1.8 TB/year → one big server, for now
2Writes: 2,000 orders/sec × 5 writes = 10,000 writes/sec → near one server's limit
3
4Grow 10× → ~18 TB/year and 100,000 writes/sec → shard

Saying "we don't need to shard yet, here's the math" is a strong interview answer.

The Two Decisions

Every sharding design answers two questions:

  1. What do we shard by? → the shard key, the field that groups data.
  2. How do we place key values on shards? → the distribution strategy: range or hash.
1order { user_id: 42, ... }
2 │
3 shard key = user_id
4 │
5 distribution: hash(42) → shard 2

Decision 1: Choosing a Shard Key

A good shard key has three properties:

PropertyMeaningWhy it matters
High cardinalityMany distinct valuesData can spread across many shards
Even distributionValues and traffic spread evenlyNo shard takes most of the load
Query alignmentPresent in your most common queriesA common query hits one shard

For our orders:

Shard keyVerdictWhy
user_idGoodMillions of users, evenly spread, and "My Orders" hits one shard
order_idOKGood spread, but "My Orders" would hit every shard
cityBadFew values, and one big city overloads its shard
is_vegBadOnly 2 values, so at most 2 shards
created_atBadAll new orders land on the newest shard

The shard key is very hard to change later. MongoDB can reshard a collection, but it copies the whole collection, so pick carefully up front.

Decision 2: Range vs Hashed Sharding

Range sharding splits the key into continuous ranges, like a dictionary split into volumes A–H, I–P, Q–Z.

Hashed sharding runs the key through a hash function (a formula that turns any value into a scrambled number) and uses that number to pick a shard. Neighbouring keys land on different shards.

1Range (by user_id) Hashed (by hash(user_id))
2Shard 1: 1 – 10M user 41 → Shard 3
3Shard 2: 10M – 20M user 42 → Shard 1
4Shard 3: 20M – 30M ← all new users user 43 → Shard 2 ← neighbours scattered
RangeHashed
Data spreadCan be unevenEven
Increasing keys (ids, timestamps)All new writes hit the last shard: a hot shardWrites spread evenly
Range query on the shard key (user_id BETWEEN 100 AND 200)Hits one or a few shardsHits all shards
Exact match (user_id = 42)One shardOne shard
Choose whenRange queries matter and keys are not ever-increasingEven spread matters most (the usual default)

Growing a hashed setup. Plain hash(key) % number_of_shards moves most data when you add a shard:

13 shards → 4 shards: hash % 3 becomes hash % 4
2→ about 3 out of 4 keys move to a different shard

Consistent hashing places keys and shards on a ring; each key goes to the next shard along the ring. Adding a fourth shard moves only about a quarter of the keys. Hash + consistent hashing is the usual default, and interviewers assume it when you say "shard by user_id".

A third option, directory sharding, keeps a lookup table of which key lives on which shard. It's flexible but adds an extra lookup per request and a single point of failure, so use it only for special cases.

sh.enableSharding("food");
// hashed: even spread
sh.shardCollection("food.orders", { userId: "hashed" });
// range: good for range queries on the key
// sh.shardCollection("food.orders", { userId: 1 });

Problems Sharding Creates

ProblemExampleFixes
Hot shardShard by restaurant_id, one hugely popular restaurant during a saleCompound key (restaurant_id + bucket 0–9) to spread it; or a dedicated shard for very busy keys
Cross-shard querySharded by user_id, but "today's orders for restaurant 7" must ask every shard and merge (scatter-gather)Better shard key; cache the result; denormalize into a copy sharded by restaurant_id
Cross-shard transactionWallet transfer between two users on different shardsKeep related data on one shard; saga (steps with undo actions); 2PC (correct but slow and fragile)
1Saga: wallet transfer, user A (shard 1) → user B (shard 3)
2Step 1: deduct ₹200 from A ✓
3Step 2: add ₹200 to B ✗ fails
4Undo: refund ₹200 to A ✓ → back to a correct state

If a common query keeps hitting every shard, the shard key is probably wrong.

Interview Angle

How to Explain it in an Interview

The 30-Second Spoken Pitch
"I shard only when the numbers show one database can't handle the storage or write load, after scaling up, indexing, caching, and replicas. Sharding needs two decisions. First, the shard key: it should have high cardinality, spread evenly, and match the main queries. For the food delivery app, I'd shard orders by user ID, so My Orders hits a single shard. Second, the distribution: range sharding keeps nearby keys together, which helps range queries but creates a hot shard when keys keep increasing. Hashed sharding spreads data evenly, and with consistent hashing, adding shards moves only a small part of the data, so that's my default. The trade-offs are hot keys, cross-shard queries, and cross-shard transactions, which I'd handle with compound keys, caching or denormalized copies, and sagas."

Common mistakes:

  • Sharding by reflex, without showing that one server isn't enough.
  • Picking a timestamp or auto-increment id with range sharding.
  • Not naming the shard key explicitly, with a reason.

Summary

1Sharding → split data across servers → scales writes + storage
2Need it? → only when the math says one server can't keep up
3Shard key → high cardinality + even spread + matches main queries
4Range → good for range queries, hot shard on increasing keys
5Hashed → even spread, range queries hit all shards
6Default → hash + consistent hashing
7Problems → hot shard, cross-shard queries, cross-shard transactions

With data spread over many servers, network failures between them are unavoidable. Next, the CAP theorem explains what a distributed database must give up when that happens.

Next TopicRange vs Hashed Sharding