Sharding and horizontal scaling

Understand routers, config servers and chunks, choose a shard key that keeps queries targeted and writes even, and know when sharding is the wrong answer.

How a sharded cluster is put together

ComponentRole
mongosQuery router; applications connect here, never directly to a shard
Config serversStore the chunk-to-shard map and the cluster metadata
ShardA replica set holding a subset of the data
Shard keyThe indexed field or fields that decide placement
ChunkA contiguous range of shard-key values; the unit the balancer moves
BalancerMoves chunks so that shards stay evenly loaded
sh.enableSharding("shop");

sh.shardCollection("shop.orders", { customerId: "hashed" });
sh.shardCollection("shop.events", { tenantId: 1, createdAt: 1 });

sh.status();
sh.getBalancerState();
db.orders.getShardDistribution();

Choosing a shard key

  • High cardinality: a field with ten distinct values can produce at most ten chunks, no matter how many shards you add.
  • Even write distribution: a monotonically increasing key such as a timestamp sends every insert to the same shard until a chunk splits.
  • Present in your queries: if the filter contains the shard key, mongos routes to one shard; otherwise it scatters to all of them.
  • A hashed key spreads writes evenly but turns range queries into scatter-gather, because neighbouring values are no longer adjacent on disk.
  • A compound key gives you both: a hashed or tenant prefix for distribution plus a range field for locality within a tenant.
// targeted: the filter contains the shard key
db.orders.find({ customerId: "c-42", placedAt: { $gte: ISODate("2026-01-01") } })

// scatter-gather: no shard key, so every shard is asked
db.orders.find({ status: "paid" })
⚠️
Treat the shard key as close to permanent. Since 5.0 a collection can be resharded, but it is a long, resource-heavy operation. Prototype the key against a realistic data volume and query mix before the collection is large, not after.

Scaling without surprises

  • Durability is unchanged by sharding: each shard is its own replica set, so a majority write concern is still satisfied inside that set.
  • A unique index is only globally enforced if the unique field has the shard key as a prefix. Otherwise uniqueness is per shard, which is usually not what you meant.
  • Pre-split and pre-place chunks when loading a large dataset, so the balancer is not doing the work while the import runs.
  • A sharded cluster costs more to operate: one router per application host, redundant config servers, and an extra network hop for every scatter-gather query.
  • Add shards when writes are the bottleneck. A read-heavy workload is usually fixed by indexes and replicas, at a fraction of the complexity.
sh.moveChunk("shop.orders", { customerId: "c-9999" }, "shard02");
sh.splitAt("shop.orders", { customerId: "c-5000" });

sh.balancerStop();
sh.balancerStart();

FAQ

When should I shard?
When a single replica set can no longer hold the working set in RAM or absorb the write throughput, or when data must be physically co-located by region. Sharding is an operational commitment, so exhaust schema, index and instance-size options first.
Why are some queries slow only in a sharded cluster?
Usually because they omit the shard key, so mongos broadcasts to every shard and merges the results. Add the shard key to the filter, or create an index on each shard for the fields you do filter on.

Replica sets, failover and read preferences Indexes and schema design patterns

Last refreshed 2026-09-18.