Partition data across multiple stores by a key, so the system scales past what a single database node can hold or serve.
A single database instance has finite storage, memory, and throughput. Once a table's data volume or write rate outgrows what one node can handle well, adding more application servers in front of it doesn't help — the database itself is the bottleneck.
Data is partitioned across multiple database instances (shards) based on a chosen key — often a user ID or tenant ID. A routing layer computes which shard owns a given key and directs reads and writes there. Each shard only holds a fraction of the total data.
`shardFor(key)` deterministically picks the same shard for the same key every time, so reads and writes for that key always land in the same place.
const shards = [
{ name: "shard-0", data: new Map() },
{ name: "shard-1", data: new Map() },
{ name: "shard-2", data: new Map() },
];
function hash(key) {
let h = 0;
for (const char of key) h = (h * 31 + char.charCodeAt(0)) >>> 0;
return h;
}
function shardFor(key) {
return shards[hash(key) % shards.length];
}
function writeUser(id, data) {
const shard = shardFor(id);
shard.data.set(id, data);
console.log(`wrote ${id} to ${shard.name}`);
}
function readUser(id) {
return shardFor(id).data.get(id); // routes to the same shard deterministically
}
writeUser("user-42", { name: "Alex" });
writeUser("user-99", { name: "Sam" });
console.log(readUser("user-42"));