Overview
Sharding scales a database horizontally by splitting one logical dataset across many physical shards, and the shard key, the field (or fields) used to decide which shard a document lives on, is the single most consequential choice in the whole design. A low-cardinality shard key concentrates most data onto too few shards; a monotonically increasing key (a sequential ID, a timestamp) is worse under range-based sharding specifically, every new write's value is higher than everything already inserted, so all new writes land on whichever single shard currently owns the highest range, a hot shard problem that gets worse the more the cluster grows, not better. Hashed sharding fixes that distribution problem by scattering even monotonic keys across shards via their hash, at a real, structural cost: a range query on the original key can no longer target one shard, since the corresponding hashes are scattered everywhere, and becomes a broadcast query across the whole cluster instead.
Quick Reference
| Sharding strategy | Distribution | Range query locality |
|---|---|---|
| Ranged | By actual shard-key value ranges | Good, a range query can target one shard |
| Hashed | By hash of the shard-key value | Poor, range queries broadcast across shards |
| Shard key problem | Cause | Result |
|---|---|---|
| Low cardinality | Few distinct values, skewed real-world frequency | Most data lands on one shard |
| Monotonically increasing | Every new value is higher than the last | All new writes hit one shard |
Syntax
// Ranged sharding - good for range queries, bad for a monotonic key
sh.shardCollection("mydb.events", { createdAt: 1 });
// Hashed sharding - even distribution, even for monotonic keys
sh.shardCollection("mydb.events", { userId: "hashed" });Examples
// A sequential/monotonic shard key concentrates every new insert
// on whichever shard currently owns the highest range.
sh.shardCollection("mydb.users", { userId: 1 });
// All new inserts land on one shard, the classic hot-shard case.
// Fixed with hashed sharding on the same field.
sh.shardCollection("mydb.users", { userId: "hashed" });Hashed sharding trades away range-query locality
Fixing a hot shard with hashed sharding means a query filtering a range of the original key (recent timestamps, a sequential ID range) can no longer be routed to one shard, it becomes a broadcast query across every shard in the cluster. This is a real trade-off, not a free fix.
Visual Diagram
Common Mistakes
- Choosing a shard key with high theoretical cardinality but skewed real-world value frequency, still producing a hot shard despite "enough" distinct values existing.
- Using a sequential ID or timestamp as a range-sharded key without recognizing it guarantees all new writes concentrate on one shard.
- Switching to hashed sharding to fix a hot shard without accounting for the resulting loss of range-query locality across the cluster.
- Assuming a shard key choice is easily reversible; resharding an existing large collection is documented as resource-intensive, not a quick fix.
Performance
- A hot shard bottlenecks the entire cluster's write throughput on one node's capacity, regardless of how many total shards exist, adding more shards doesn't help until the key itself is fixed.
- Hashed sharding's range-query cost is real and structural: a query that would hit one shard under ranged sharding becomes a broadcast across every shard under hashed sharding, a direct latency and load cost on that query pattern.
Best Practices
- Choose a shard key with genuinely even real-world value distribution, not just high theoretical cardinality.
- Avoid monotonically increasing fields as a ranged shard key; use hashed sharding specifically for fields that increase this way.
- Weigh write-distribution needs against read-pattern needs before choosing ranged versus hashed, they optimize for different things.
- Treat shard key choice as a decision to get right upfront, resharding later is documented as resource-intensive, not a routine operation.