Partitioning and Sharding
Partitioning splits one table across pieces of one database; sharding splits data across separate database nodes — and everything that crosses a shard boundary (joins, transactions, uniqueness, aggregates) becomes the application’s problem.
The difference
Partitioning divides one logical table into physical pieces within a single database. Same machine, same transactions, same joins, same constraints — the planner just prunes the partitions a query does not need and each piece stays small. It solves *operability* of a huge table: small indexes, fast VACUUM, instant retention by dropping a partition. It does not add capacity.
Sharding divides data across independent database nodes, each a full database serving a slice of the keyspace. It is the only thing that adds write capacity beyond one machine. The price is that anything spanning shards — a join, a transaction, a unique constraint, a count(*) — now happens in application code, if it can happen at all.
Choosing the shard key
The shard key decides which node holds a row, and the goal is that almost every query already knows it. Hash sharding (hash(user_id) mod N) spreads load evenly regardless of the key’s distribution, at the cost of range queries hitting every shard and resharding remapping almost everything (consistent hashing or virtual nodes soften that). Range sharding (A–F, G–M) keeps ranges on one shard but skews with the data — and with a monotonically increasing key, every new row lands on the last shard, the classic hot shard. Geographic sharding gives locality and data-residency compliance and wildly uneven shard sizes. Tenant sharding (all of one account on one shard) keeps almost every query shard-local for B2B SaaS, until one whale tenant outgrows its shard.
The failure to design for is the hot shard: a key whose distribution concentrates traffic on one node, which then gets a majority of the load on a minority of the hardware, and adding shards does not help because the key is the problem.
What crosses the boundary
A query that names the shard key touches one shard and is fast. A query that does not is scatter-gather: sent to every shard, results merged in the application — slow, and it gets slower as you add shards. Joins across shards are done in application code or not at all. Transactions across shards need two-phase commit (slow, and a coordinator failure leaves locks held) or a saga (application-level compensation). Global uniqueness — a unique email across all shards — needs a separate lookup service, because no single shard can enforce it. count(*) over everything is scatter-gather.
This is why sharding is last on the ladder. It is not a config change; it is a re-architecture that trades a whole category of database guarantees for horizontal write scale. Exhaust vertical scaling, replicas, caching and partitioning first, genuinely.
1-- PARTITIONING: one database, planner prunes, retention is instant2CREATE TABLE events (occurred_at timestamptz, ...) PARTITION BY RANGE (occurred_at);3CREATE TABLE events_2026_01 PARTITION OF events FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');4 5-- SHARDING: many databases, routing in the application, no cross-shard join6-- shard = hash(tenant_id) % 4 → connect to that node, query only there7-- "list all tenants over quota" → ask all 4 nodes, merge in code (scatter-gather)Key points
- Partitioning: one database, smaller pieces, no new capacity. Sharding: many databases, real write scale, lost cross-shard guarantees.
- The shard key must be in almost every query; hash spreads evenly, range and tenant skew into hot shards.
- Cross-shard joins, transactions, uniqueness and aggregates move into the application or disappear.
- Shard last, after vertical scaling, replicas, caching and partitioning are exhausted.
Four ways to shard
Shard 1 gets A–F, shard 2 G–M, and so on. Easy to reason about and range queries stay on one shard.
When to use — and when not
- Partitioning: any table growing past hundreds of millions of rows with a natural time or tenant key. Sharding: a measured single-machine write ceiling.
- Sharding for read scaling (use replicas) or before vertical scaling is exhausted.
- Partitioning by a column queries do not filter on.
Failure modes
- A shard key that concentrates load — hot shard.
- Scatter-gather queries that scale with shard count.
- Cross-shard transactions bolted on after the fact.
- Resharding a hash scheme that remaps every key.
See how this works internally →
Descend one layer: the same topic explained from the machinery up.