What Is Sharding? A Complete, Beginner‑Friendly Guide
How giant applications like Amazon, Instagram, and Uber store billions of rows of data without falling over — explained from first principles, with diagrams, Java code, and honest production trade‑offs.
Introduction & History
One librarian and one bookshelf works fine for a hundred books. Ten million books need a whole city of branch libraries. Sharding is how the internet solved that same problem for data.
Picture a school library with a single librarian and a single bookshelf. When there are a hundred books on that shelf, the librarian can find any one of them in seconds. But what happens when the library’s collection grows to ten million books? One shelf cannot hold them. One librarian cannot remember where every title lives. Every student ends up standing in a long line just to ask a simple question.
That is exactly the situation big websites and apps eventually run into with their data. In the early years of the internet, a single database sitting on a single computer was more than enough to power an entire application. As companies grew from thousands of users into hundreds of millions, one database was no longer close to enough. Engineers needed a way to split their data across many computers while still making it feel like “one library” to the people using it.
That solution is called sharding.
Think of sharding as splitting one enormous library into ten smaller branch libraries scattered across a city. Each branch holds a portion of the books — maybe titles starting A–C live at Branch 1, D–F at Branch 2, and so on. When you want a book, you do not search all ten branches. You walk straight to the right one, guided by a simple rule (the first letter of the title). Sharding does the very same thing with data.
A short history
The word “shard” literally means a small broken piece of something larger — a shard of glass or pottery. The idea of splitting data across machines is older than the modern web; mainframe systems in the 1980s already used a technique called “horizontal partitioning” to spread large tables across storage devices.
The term “sharding” in its modern sense took off in the early 2000s, largely thanks to massively multiplayer online games (MMOs) like Ultima Online and EverQuest. Those games split their game world into multiple parallel copies called “shards” — each shard being a separate server that held a subset of players and game state, so the game as a whole could support far more players than any single server could.
Around the same era, web companies like Google, Amazon, and later Facebook, Twitter, and Uber were hitting the very same wall with their relational databases. Google’s Bigtable paper (2006) and Amazon’s Dynamo paper (2007) popularised the idea of automatically partitioning data across thousands of commodity machines. From there, sharding rapidly became a standard pattern — taught in every system design course and asked about in nearly every senior engineering interview.
Sharding is one of the most frequently discussed topics in system design interviews at companies like Amazon, Google, Meta, and Uber — because almost every large‑scale system eventually needs it. Understanding it deeply is one of the highest‑leverage things a software engineer can learn.
The Problem Sharding Solves
To really understand sharding, you first have to understand the problem it fixes: a single database server running out of room to grow. Every machine has walls, and eventually one of them is what a system hits first.
To understand sharding, you first need to understand the problem it exists to fix: a single database server, no matter how expensive, running out of room to grow.
The limits of a single database server
Every computer, however powerful, has physical limits:
- Storage limit — a hard disk or SSD can only hold so much data.
- Memory (RAM) limit — only so much data can be cached in memory for fast access.
- CPU limit — only so many queries can be processed per second.
- Network limit — only so much data can move in and out over the network per second.
When a company is small, none of that matters. But as the number of users and the volume of data climbs into the millions or billions of rows, a single machine — no matter how expensive — eventually cannot keep up. Engineers call the moment you hit this a “scaling wall.”
Vertical scaling vs. horizontal scaling
There are two broad ways to deal with a database that is running out of capacity:
Vertical Scaling
Buy a bigger, more powerful machine — more CPU, more RAM, more disk. Simple, but has a hard ceiling and gets extremely expensive at the high end. Eventually, no single machine is big enough.
Horizontal Scaling
Add more machines instead of a bigger one, and split the work — and the data — across them. This is exactly where sharding comes in.
Vertical scaling is like hiring one super‑strong person to carry every box in a warehouse by themselves — you can only make them so strong. Horizontal scaling is like hiring ten regular workers, each carrying a portion of the boxes. Ten normal workers can move far more than one super‑strong worker ever could, and it is cheaper too.
Sharding vs. replication — not the same thing
Beginners often confuse sharding with replication, but the two solve genuinely different problems:
| Aspect | Sharding | Replication |
|---|---|---|
| What it does | Splits different data across servers | Copies the same data across servers |
| Main goal | Handle more data & more write throughput | Handle more read throughput & provide backups |
| Each server has | A unique subset of the data | A full copy of the data |
| Failure impact | Losing a shard loses that portion of data | Losing a replica does not lose any data |
In real production systems, sharding and replication are almost always used together: every shard is itself replicated for safety. We will return to this combination later in the High Availability chapter.
Core Concepts
Eight short definitions to keep in your pocket. Master these, and every other section in this guide clicks into place.
3.1 What is sharding?
Sharding (also known as horizontal partitioning) is the process of splitting a large dataset into smaller, independent pieces called shards, and then storing each shard on a separate database server. Every shard holds a different subset of the rows in a table, but all shards together share the exact same table structure (columns).
Imagine you have a huge box of 1,000 LEGO bricks and only one small drawer to store them in. Instead of cramming everything into that one drawer (which will not fit), you buy ten drawers and split the bricks — red bricks in drawer 1, blue in drawer 2, and so on. Finding a red brick is now fast because you already know exactly which drawer to open. That is sharding — many drawers, each holding a slice of the whole collection, with a clear rule for what goes where.
3.2 Horizontal vs. vertical partitioning
It helps to clearly separate two often‑confused ideas:
- Horizontal partitioning (sharding) — splits a table by rows. Users 1–1,000,000 go to Shard A, users 1,000,001–2,000,000 go to Shard B. Every shard has the same columns.
- Vertical partitioning — splits a table by columns. For instance, keeping frequently‑used columns (name, email) in one table and rarely‑used columns (biography, preferences) in another, possibly on a different server.
When people say “sharding” without further context, they almost always mean horizontal partitioning across multiple servers. This tutorial focuses entirely on that meaning.
3.3 Shard key (partition key)
The shard key is the piece of data used to decide which shard a particular row belongs to. Picking the shard key is the single most important design decision in a sharded system — a poor choice can quietly undo all the benefits of sharding.
If you are sharding a users table by user_id, the shard key is user_id. A rule as simple as shard_number = user_id % 4 could decide which of four shards stores that user’s row.
3.4 Shard (partition, node)
A shard is one independent database instance that holds a slice of the total data. Each shard is a fully working, self‑contained database with its own storage, memory, and processing power. Shards do not share data with each other — they only know about their own slice.
3.5 Logical shard vs. physical shard
Modern systems often separate the concept of a “logical shard” (a bucket, e.g. “bucket 173 of 1024”) from a “physical shard” (an actual database server). Many logical shards can be mapped onto one physical server. That extra layer of indirection makes it much easier to move data around later without touching the shard key logic — we will unpack this under Consistent Hashing.
3.6 Shard map / routing layer
The shard map (or routing table) is the lookup table that tells the application which physical shard holds a given logical shard or key range. A router or proxy component uses this map to send each query to the correct shard.
3.7 Rebalancing
Rebalancing is the process of moving data between shards after they are already created — usually because one shard has grown much larger or busier than the others (a “hot shard”). This is one of the hardest operational challenges in any sharded system.
3.8 Cross‑shard query
A cross‑shard query is any query that needs data from more than one shard (for example, “find the total number of orders across all customers”). These queries are slower and more complex than single‑shard queries because the application has to ask multiple shards in parallel and combine the results itself.
Architecture & Components
A production sharded system typically has five building blocks working together. The application talks to a router, the router consults a shard map, and the router forwards the request to the right shard — not the other way around.
A production sharded system typically has five building blocks working in concert.
Application Layer
The service code that reads and writes data. It usually does not talk to shards directly — it goes through a routing layer.
Router / Proxy
Decides, for every incoming request, which shard(s) to contact, based on the shard key and the shard map.
Shard Map / Config Service
A small, highly‑available store (like ZooKeeper, etcd, or a config database) that tracks which shard owns which data range.
Shards
The actual database instances — each storing one slice of data, and usually each replicated for durability.
Rebalancer / Orchestrator
A background process or tool that monitors shard load and moves data when shards become uneven (“hot” or “cold”).
Vitess, the sharding system built at YouTube and now used by Slack, GitHub, and Square, uses exactly this pattern: a proxy called VTGate handles routing, while a component called the “topology service” (backed by etcd or ZooKeeper) stores the shard map.
Where routing logic can live
| Approach | Description | Used By |
|---|---|---|
| Client‑side routing | The application itself contains the sharding logic and connects directly to the right shard. | Early Facebook MySQL sharding, custom in‑house systems |
| Proxy‑based routing | A separate proxy service sits between the app and the shards, hiding the sharding logic. | Vitess (YouTube), ProxySQL, Citus |
| Database‑native routing | The database engine itself is shard‑aware and handles routing internally. | MongoDB (mongos), Google Spanner, CockroachDB, Cassandra |
Levels of sharding maturity
Teams tend to move through a predictable set of stages as their data grows, and it helps to recognise where you are on this ladder:
- Single database — one server handles everything. Perfectly fine for most applications, even fairly large ones.
- Vertical scaling + read replicas — a bigger primary server for writes, with read‑only copies to spread out read traffic. This alone solves the majority of early scaling problems.
- Functional federation — splitting one big database into several databases by subject area (users, orders, payments), each still a single server.
- Sharding — one or more of those functional databases is further split horizontally across multiple servers, because a single server can no longer hold that subject area’s data or traffic.
- Globally distributed sharding — shards spread not just across servers but across regions and continents, often using a distributed SQL database, so a worldwide user base gets low latency everywhere.
Very few companies ever need to reach stage 5. Recognising which stage your system is actually at — rather than assuming you need the most advanced setup — is one of the most valuable skills an architect can develop.
How Sharding Works Internally
At the heart of every sharded system is one small function: given a piece of data, tell me which shard it belongs to. Five common ways to answer that question — each with its own personality.
The heart of sharding is the function that decides, for any given piece of data, which shard it belongs to. This is called the partitioning function or sharding algorithm. Let’s walk through the five approaches you will see most often.
5.1 Hash‑based sharding
The shard key is passed through a hash function (a function that converts input into a fixed‑size number that looks random but is always the same for the same input). The hash result is then used, usually with a modulo operation, to pick a shard.
shard_number = hash(shard_key) % number_of_shards
Imagine writing every student’s name on a slip of paper, feeding it into a magic machine that scrunches the name into a random‑looking number, and then using the last digit of that number to decide which of ten classrooms they belong to. Every student ends up in a classroom, and because the “magic number” looks random, students get spread out roughly evenly across all ten classrooms — even if their names all start with the same letter.
Why hashing helps
Hash‑based sharding spreads data evenly and avoids “hot spots” — situations where one shard gets far more traffic than the others. That is its biggest advantage over simple range‑based splitting.
The big weakness: adding or removing shards
The formula hash(key) % N has a serious problem: if N (the number of shards) changes — say you grow from four shards to five — almost every key’s hash % N result changes as well. Which means almost all the data must be moved around at once, which is extremely expensive and disruptive in a live production system.
Using plain modulo hashing in a system that needs to grow is a classic beginner mistake. It works fine on day one, but becomes a painful, risky migration the day you need to add servers. This is exactly the problem that consistent hashing was invented to solve.
5.2 Consistent hashing
Consistent hashing is a smarter hashing technique, introduced in a 1997 paper by Karger et al. at MIT, and popularised in production by Amazon’s Dynamo paper. It dramatically reduces how much data needs to move when shards are added or removed.
Here is how it works, step by step:
- Imagine a circle (a “ring”) representing all possible hash values, from 0 up to some very large number, wrapping back round to 0.
- Each shard (server) is placed at one or more points on this ring, based on hashing the server’s name or ID.
- Each piece of data is also hashed to find its own position on the ring.
- To find which shard owns a piece of data, walk clockwise from the data’s position until you hit the first shard.
The magic of consistent hashing: when a new shard is added, it only takes over a small slice of the ring from its neighbour. All other shards are completely unaffected. Instead of moving nearly 100% of the data (as with plain modulo hashing), you typically only move about 1/N of the data, where N is the new number of shards.
Virtual nodes
In practice, each physical shard is given many points on the ring (called “virtual nodes” or “vnodes”) instead of just one. That spreads load more evenly and makes rebalancing smoother when a shard is added or removed. Cassandra, DynamoDB, and Riak all use virtual nodes internally.
5.3 Range‑based sharding
Data is split according to ranges of the shard key’s value. For example, customer IDs 1–1,000,000 go to Shard A, 1,000,001–2,000,000 go to Shard B, and so on.
Advantage
- Range queries (e.g. “all orders from January”) are efficient, because related data sits together on the same shard.
Disadvantage
- Can create “hot shards” — for example, if IDs are assigned sequentially, all new users land on the newest, single shard while older shards sit idle.
Google’s Bigtable and HBase use range‑based sharding, splitting tables into contiguous “tablets” by row key. Because time‑series and analytics workloads often query by range (e.g. “events from last week”), that trade‑off makes sense for those systems.
5.4 Directory‑based (lookup table) sharding
Instead of computing the shard with a formula, a separate lookup service simply stores, for every key, exactly which shard it lives on. This is the most flexible approach because any key can be moved to any shard just by updating the lookup entry — no formula, no ring, just a map.
Advantage
- Maximum flexibility. Rebalancing is just updating a row in the lookup table.
Disadvantage
- The lookup service itself becomes a critical dependency and potential bottleneck — it must be fast, highly available, and heavily cached.
5.5 Geo‑based sharding
Data is split by geography — European users’ data stays on shards in Europe, US users’ data stays on shards in the US, and so on. This is increasingly common not just for performance (keeping data close to users reduces latency) but also for legal compliance, such as GDPR requirements that certain data must stay within specific countries or regions.
Data Flow & Lifecycle
Follow one request from application to storage — a single‑shard write, a single‑shard read, and the scatter‑gather query that fans out to every shard at once.
Let’s trace exactly what happens when an application reads and writes sharded data, from request to response.
Write path
- The application sends a write request, e.g. “create an order for customer 8842.”
- The router extracts the shard key (
customer_id = 8842). - The router computes or looks up the target shard (e.g. Shard 3).
- The write is sent only to Shard 3 and its replicas.
- Shard 3 acknowledges the write; the router returns success to the application.
Read path (single‑shard query)
- The application asks “get all orders for customer 8842.”
- The router computes the shard for
customer_id = 8842— again Shard 3. - The query goes directly to Shard 3 (or one of its read replicas).
- Shard 3 returns the result; the router passes it back unchanged.
Read path (cross‑shard / scatter‑gather query)
Some queries do not include the shard key — for example, “find all orders placed today across the entire company.” The router cannot know which single shard holds the answer, because the data is spread across all of them.
This pattern is called scatter‑gather (or fan‑out). It works, but it is inherently slower and more resource‑intensive than a single‑shard query, because the overall response time is limited by the slowest shard, and the results must then be merged, sorted, or aggregated in application code.
Because cross‑shard queries are expensive, a well‑designed sharded system tries to make the shard key match the most common query pattern — so that the vast majority of queries only touch one shard.
Choosing a Good Shard Key
If sharding has one make‑or‑break decision, it is the shard key. Four qualities separate a great key from one that quietly ruins the system a year after launch.
If sharding has one “make‑or‑break” decision, it is the shard key. A poorly chosen key can create imbalanced shards, excessive cross‑shard queries, or both. Here are the qualities to look for.
Qualities of a good shard key
- High cardinality — many distinct possible values, so data spreads across many shards (e.g.
user_idis good;countrywith only five values is risky). - Even distribution — no single value should be dramatically more common than others (avoids “hot” shards).
- Matches query patterns — most of your application’s queries should already include this key, so most reads and writes stay on a single shard.
- Rarely changes — changing a row’s shard key means physically moving the row to a different shard, which is expensive.
Instagram famously shards its Postgres database by user ID. Because nearly every query (“show this user’s photos,” “show this user’s followers”) naturally includes the user ID, that choice keeps the overwhelming majority of queries on a single shard.
Common anti‑pattern: sharding by a low‑cardinality field
A beginner mistake is sharding by something like status (“active”/“inactive”) or country. If 90% of users are in one country, that shard becomes massively overloaded while the others sit nearly empty — defeating the entire purpose of sharding.
Java example: a simple hash‑based router
Below is a simplified Java example showing how a router might decide which shard to send a query to, using a basic hash‑based approach.
public class ShardRouter {
private final int numberOfShards;
public ShardRouter(int numberOfShards) {
this.numberOfShards = numberOfShards;
}
// Decides which shard a given key belongs to
public int getShardForKey(String shardKey) {
int hash = Math.abs(shardKey.hashCode());
return hash % numberOfShards;
}
public static void main(String[] args) {
ShardRouter router = new ShardRouter(4);
String[] userIds = {"user_101", "user_202", "user_303", "user_404"};
for (String userId : userIds) {
int shard = router.getShardForKey(userId);
System.out.println(userId + " -> Shard " + shard);
}
}
}
This works, but as we discussed earlier, it suffers from the “almost everything moves” problem when numberOfShards changes. Here is a simplified consistent hashing implementation that avoids that issue.
import java.util.SortedMap;
import java.util.TreeMap;
public class ConsistentHashRouter {
private final SortedMap<Long, String> ring = new TreeMap<>();
private final int virtualNodesPerShard;
public ConsistentHashRouter(int virtualNodesPerShard) {
this.virtualNodesPerShard = virtualNodesPerShard;
}
public void addShard(String shardName) {
for (int i = 0; i < virtualNodesPerShard; i++) {
long hash = hash(shardName + "#VN" + i);
ring.put(hash, shardName);
}
}
public void removeShard(String shardName) {
ring.values().removeIf(name -> name.equals(shardName));
}
public String getShardForKey(String key) {
long hash = hash(key);
// Find the first shard clockwise from this hash value
SortedMap<Long, String> tail = ring.tailMap(hash);
Long nodeHash = tail.isEmpty() ? ring.firstKey() : tail.firstKey();
return ring.get(nodeHash);
}
private long hash(String input) {
// A simple, deterministic 64-bit hash (production code should use
// MD5, MurmurHash, or a similar well-tested hash function)
long h = 1125899906842597L;
for (char c : input.toCharArray()) {
h = 31 * h + c;
}
return h;
}
public static void main(String[] args) {
ConsistentHashRouter router = new ConsistentHashRouter(100);
router.addShard("ShardA");
router.addShard("ShardB");
router.addShard("ShardC");
System.out.println("user_101 -> " + router.getShardForKey("user_101"));
System.out.println("user_202 -> " + router.getShardForKey("user_202"));
// Adding a new shard only remaps a small fraction of keys
router.addShard("ShardD");
System.out.println("After adding ShardD:");
System.out.println("user_101 -> " + router.getShardForKey("user_101"));
}
}
In real production systems, engineers rarely write their own hashing router from scratch. They rely on battle‑tested tools like Vitess, Citus, MongoDB’s built‑in sharding, or DynamoDB’s managed partitioning — which implement these ideas with years of edge‑case handling already baked in.
Advantages, Disadvantages & Trade‑offs
Sharding is powerful, but it is not free. The same properties that make it scale also introduce operational complexity that every architect eventually has to reckon with.
Advantages of sharding
| Benefit | Explanation |
|---|---|
| Horizontal scalability | You can keep adding shards as data grows, instead of hitting a hard ceiling on a single machine. |
| Improved write throughput | Writes are spread across many independent servers instead of funnelling through one. |
| Smaller, faster indexes | Each shard only indexes its own slice of data, so lookups and index maintenance are faster. |
| Fault isolation | If one shard has a problem, only the data on that shard is affected — not the entire system. |
| Geographic performance | Data can be placed physically closer to the users who use it most, cutting network latency. |
Disadvantages of sharding
| Drawback | Explanation |
|---|---|
| Operational complexity | Instead of managing one database, teams now manage many — with more moving parts, more monitoring, and more things that can go wrong. |
| Cross‑shard queries are hard | Joins, aggregations, and transactions across shards need extra application logic and are slower. |
| Rebalancing is risky | Moving data between shards while the system is live is one of the trickiest operations in distributed systems. |
| Harder schema changes | A schema migration must now be applied consistently across every shard. |
| Uneven load (“hot shards”) | A poorly chosen shard key can overload one shard while others sit idle. |
Sharding is a powerful tool, but it is not free. Many teams shard too early, before they actually need it, and pay the operational cost without earning the benefit. A widely repeated piece of engineering wisdom captures it well: “Don’t shard until you have to — and when you do, plan for it carefully.” Vertical scaling, read replicas, and caching should usually be tried first.
Performance & Scalability
Doubling shards roughly doubles capacity — in theory. In practice, hot shards, tail latency, and network hops all decide whether that potential is real.
The whole point of sharding is scalability, so it is worth understanding precisely how it improves performance — and where its limits are.
Linear (near‑linear) scalability
In an ideal sharded system, doubling the number of shards roughly doubles the total write capacity, because each shard independently handles its own slice of traffic with no shared bottleneck. In practice, scalability is “near‑linear” rather than perfectly linear, because of overhead from routing, cross‑shard queries, and coordination.
Hot shards and skew
A “hot shard” is one that receives disproportionately more traffic or data than the others, becoming a bottleneck even though the system as a whole has spare capacity elsewhere. This is the single biggest threat to sharding’s performance benefits, and it almost always traces back to a poor shard key choice, or to a naturally skewed real‑world distribution (for example, a small number of extremely popular users or products).
On social platforms, a small number of celebrity accounts can receive millions of times more traffic than an average user — a phenomenon sometimes called “the celebrity problem.” Engineering teams at large social networks have written about needing specialised handling for such outlier accounts, since normal sharding assumptions break down for them.
Query latency considerations
- Single‑shard queries stay fast, because each shard is small and the query never leaves one machine.
- Cross‑shard queries are bound by the slowest participating shard, plus the time it takes to merge results — sometimes called the “tail latency” problem.
- Network hops matter — every extra hop (application → router → shard) adds latency, so routers are usually kept close to the shards.
High Availability & Reliability
Sharding on its own does not make a system reliable — it multiplies your points of failure. Combining sharding with replication is what turns fragile into resilient.
Sharding alone does not make a system reliable — in fact, on its own, it makes a system more fragile: with ten shards, you now have ten independent points of failure instead of one. This is exactly why sharding is almost always combined with replication.
Sharding + replication together
In production, each shard is not a single server — it is a small cluster: one primary server that accepts writes, and one or more replica servers holding up‑to‑date copies of that shard’s data. If the primary fails, a replica can be promoted to take over.
Think of each shard as one branch library, and replication as keeping two extra backup copies of every book in that branch, stored in nearby buildings. If the main branch building has a problem, the books are not lost — they still exist in the backup buildings, and a new “main” building can be declared.
Failover
Failover is the process of automatically detecting that a shard’s primary server has failed and promoting one of its replicas to become the new primary, so the system keeps working with minimal disruption. Modern systems (MongoDB replica sets, PostgreSQL with Patroni, MySQL Group Replication) automate this process using consensus protocols, typically completing failover in seconds.
Backup and disaster recovery
Because losing a shard means permanently losing that slice of data (unless replicas or backups exist), sharded systems need a disciplined backup strategy:
- Regular automated snapshots of every shard, stored separately from the shard itself.
- Point‑in‑time recovery, so a shard can be restored to its state just before a bad deployment or accidental deletion.
- Cross‑region replicas, so that an entire data centre failure does not take down every replica of a shard at once.
Consensus, CAP Theorem & Failure Recovery
Distributed systems live under three unavoidable constraints. The CAP theorem names them; consensus algorithms are how real systems make peace with them.
The CAP theorem
The CAP theorem, formalised by computer scientist Eric Brewer, states that a distributed data system can only fully guarantee two out of these three properties at the same time, during a network failure:
- Consistency (C) — every read receives the most recent write, or an error.
- Availability (A) — every request receives a (non‑error) response, even if it might not be the latest data.
- Partition Tolerance (P) — the system keeps working even if network communication between servers is broken.
Because real networks do occasionally experience partitions (a switch fails, a cable is cut, a data centre loses connectivity), partition tolerance is not really optional for a distributed sharded system — so the real, practical choice is between consistency and availability when a partition happens.
| Category | Behaviour | Examples |
|---|---|---|
| CP (Consistency + Partition Tolerance) | May refuse requests during a partition, to avoid returning wrong data. | Google Spanner, HBase, MongoDB (in default settings) |
| AP (Availability + Partition Tolerance) | Keeps answering requests during a partition, accepting that some replicas may briefly disagree. | Cassandra, DynamoDB, Riak |
Consensus algorithms
To keep replicas of a shard agreeing on who the current primary is (and what the latest committed data is), distributed systems use consensus algorithms — protocols that let a group of servers agree on a value even if some of them fail or messages get delayed.
- Raft — a consensus algorithm designed to be easy to understand; used by etcd, Consul, and CockroachDB.
- Paxos — an older, more complex consensus algorithm; used inside Google Chubby and Spanner.
Consensus is like a classroom voting on which student is “team leader” today. Even if a couple of students step out of the room briefly (a network delay), the remaining majority can still agree on one clear leader — as long as more than half the class is present and voting.
Failure recovery workflow
- Detection — a health‑check or heartbeat mechanism notices a shard’s primary is not responding.
- Election — the remaining replicas run a consensus protocol to elect a new primary.
- Promotion — the elected replica becomes the new primary and starts accepting writes.
- Re‑routing — the shard map / config service is updated, so the router sends future traffic to the new primary.
- Recovery — the failed server, once fixed, rejoins as a replica and catches up on missed data.
Security
Sharding spreads data across many servers, which means security has to be enforced consistently everywhere. A single misconfigured shard becomes a weak link for the entire system.
Sharding spreads data across many servers, which means security has to be enforced consistently everywhere — a single misconfigured shard can become a weak link for the entire system.
Key security concerns
- Consistent access control — every shard must enforce the same authentication and authorisation rules. A permission fix applied to one shard but forgotten on another creates a security gap.
- Encryption in transit — traffic between the router and shards, and between shards and their replicas, should be encrypted (TLS), especially when shards live in different data centres or cloud regions.
- Encryption at rest — each shard’s underlying storage should be encrypted, so a stolen disk or backup does not expose data.
- Network isolation — shards typically sit in private subnets, reachable only through the router/proxy layer, not directly from the public internet.
- Data residency compliance — regulations like GDPR (Europe) or data localisation laws (in countries such as India and Russia) may require that certain users’ data physically stays within specific geographic boundaries — a strong motivation for geo‑based sharding.
- Audit logging — because data is spread out, security teams need centralised, aggregated audit logs across all shards to detect suspicious patterns that might only be visible when the whole system is looked at together.
Teams sometimes apply a security patch or access control update to their “main” shard and forget to roll it out to every other shard. Because sharded systems can have dozens or hundreds of shards, security changes should always be automated and applied through infrastructure‑as‑code, never done by hand, shard by shard.
Monitoring, Logging & Metrics
With one database, monitoring is easy: watch one dashboard. With many shards, monitoring becomes an exercise in spotting the one shard out of a hundred that is quietly misbehaving.
With a single database, monitoring is simple — watch one dashboard. With many shards, monitoring becomes an exercise in spotting the one shard out of a hundred that is misbehaving.
Key metrics to track per shard
| Metric | Why It Matters |
|---|---|
| Queries per second (QPS) | Reveals hot shards receiving disproportionate traffic. |
| Storage size / row count | Reveals shards growing faster than others, signalling a need to rebalance. |
| Read/write latency (p50, p95, p99) | Slow “tail” latencies on one shard can drag down overall system performance. |
| Replication lag | How far behind a replica is from its primary — high lag risks serving stale reads or losing data on failover. |
| Error rate | Spikes in errors on a single shard often indicate hardware issues or resource exhaustion. |
| CPU / memory / disk I/O | Standard resource metrics, tracked per shard to spot imbalance. |
Aggregated dashboards
Beyond per‑shard metrics, teams build aggregated views — total QPS across all shards, the “top 5 hottest shards,” and heat maps showing load distribution — so a human operator can spot skew at a glance instead of checking a hundred separate dashboards.
Distributed tracing
For cross‑shard (scatter‑gather) queries, distributed tracing tools (such as Jaeger or Zipkin, following the OpenTelemetry standard) let engineers see exactly how long each shard took to respond within a single logical request, making it possible to pinpoint which shard is slowing everything down.
Set automated alerts on shard imbalance (e.g. “alert if any shard has more than 2x the average QPS or storage of other shards”) rather than relying on someone noticing it manually. Catching skew early makes rebalancing much easier.
Deployment & Cloud
Modern cloud platforms have made sharding far more approachable than it used to be, by offering managed services that handle much of the routing, rebalancing, and failover for you.
Modern cloud platforms have made sharding far more approachable than it used to be, thanks to managed services that handle much of the routing, rebalancing, and failover automatically.
Managed sharding services
| Service | Provider | Notes |
|---|---|---|
| Amazon DynamoDB | AWS | Fully managed, automatically shards (“partitions”) tables based on a partition key. |
| Azure Cosmos DB | Microsoft Azure | Automatically partitions data based on a chosen partition key, with configurable throughput per partition. |
| Google Cloud Spanner | Google Cloud | Globally distributed, automatically splits data into ranges and rebalances them across servers. |
| MongoDB Atlas | MongoDB Inc. | Managed sharded clusters with automatic balancing across shards. |
| Vitess / PlanetScale | Open source / PlanetScale | Adds transparent sharding on top of standard MySQL. |
| Citus | Microsoft (Postgres extension) | Turns PostgreSQL into a distributed, sharded database. |
Containerisation & orchestration
Shards are commonly deployed as stateful containers managed by Kubernetes, using StatefulSets to give each shard’s pods a stable network identity and persistent storage — since (unlike stateless web servers) shards cannot simply be swapped for an identical replacement. Each one holds unique data.
Zero‑downtime shard migrations
Moving data to a new shard while the system stays live typically follows this pattern:
- Dual writes — new writes are sent to both the old and the new shard.
- Backfill — existing data is copied from the old shard to the new one in the background.
- Verification — the new shard’s data is compared against the old shard’s to confirm correctness.
- Cutover — the router’s shard map is updated to point reads (and eventually writes) to the new shard.
- Cleanup — once confidence is high, the old copy of the data is removed.
Vitess (originally built at YouTube) pioneered this kind of “live resharding” for MySQL, allowing YouTube to split and merge shards without taking the service offline — a technique it now offers to any company running Vitess.
Databases, Caching & Load Balancing
Sharding lives alongside caching and load balancing, not instead of them. Understanding how the three interact is what turns a “sharded system” into an actually fast one.
Sharding and caching
Caching (using tools like Redis or Memcached) and sharding solve different but complementary problems. Caching keeps frequently‑accessed data in fast memory to avoid hitting the database at all; sharding spreads the database itself across multiple machines. Large systems typically use both: a cache in front of every shard, so even a single shard’s load is reduced further.
If sharding is having ten branch libraries instead of one, caching is each branch keeping its twenty most‑requested books on a small shelf right by the front door, so the librarian does not have to walk to the back room for the books people ask for most often.
Sharding and load balancing
A load balancer spreads incoming network traffic across multiple identical servers. A shard router is a specialised form of this idea — except instead of sending traffic to any available server, it sends each request to one specific, correct server based on the data being requested. Within a single shard’s replica set, a traditional load balancer is often still used to spread read traffic across that shard’s replicas.
NoSQL databases built for sharding
Some databases were designed from the ground up to be sharded automatically, without engineers having to build custom routing logic:
- MongoDB — built‑in sharding using a “shard key,” with a routing component called
mongos. - Cassandra — uses consistent hashing internally to spread data (“partitions”) across a ring of nodes with no single point of failure.
- DynamoDB — automatically partitions tables based on a partition key, scaling storage and throughput transparently.
- Elasticsearch — splits indices into “shards” for both storage and parallel query execution.
Traditional relational databases (MySQL, PostgreSQL) do not shard automatically out of the box — sharding them requires either application‑level logic, a proxy layer like Vitess or Citus, or migrating to a distributed SQL database like Google Spanner or CockroachDB that adds automatic sharding on top of SQL.
Design Patterns & Anti‑patterns
Sharded systems have their own recurring patterns — and their own recurring bad habits. Learning to name both is what separates a candidate who has read about sharding from one who has actually run it.
Useful patterns
Denormalisation
Duplicating some data across shards so common queries do not need cross‑shard joins — trading storage space for query simplicity.
Fan‑out / Scatter‑Gather
Deliberately querying all shards in parallel for reports or analytics where no single shard has the full answer.
Shard‑Aware Caching
Caching layers organised by the same shard key, so cache invalidation naturally aligns with shard boundaries.
Two‑Phase Commit / Sagas
Patterns for handling transactions that span multiple shards, since a single ACID transaction usually cannot cross shard boundaries.
Anti‑patterns to avoid
- Sharding too early — adding the complexity of sharding before the system actually needs the scale, when a bigger single server or read replicas would have been simpler.
- Sharding by a low‑cardinality or skewed key — as discussed earlier, this creates hot shards and defeats the whole purpose.
- Ignoring cross‑shard transactions until it is too late — not planning for how multi‑shard operations (like “transfer money between two users on different shards”) will be handled.
- Manual, undocumented rebalancing — moving data between shards by hand, without tooling or verification, is a common source of data‑loss incidents.
- No shard‑level monitoring — only watching aggregate, system‑wide metrics, which can hide a single badly overloaded shard.
Best Practices & Common Mistakes
A tight checklist of habits that consistently produce healthy sharded systems — plus the mistakes that quietly sink otherwise good designs six months in.
Best practices
Common mistakes
- Picking a shard key that matches today’s data, but not tomorrow’s query patterns.
- Forgetting that unique constraints (like a unique email address) are hard to enforce across shards, since each shard only sees its own slice of data.
- Underestimating how expensive and risky live rebalancing will be, and not building tooling for it early.
- Treating each shard as equally important, when in reality some shards (e.g. large enterprise customers) may need dedicated capacity.
- Not testing failure scenarios (a shard going down, a replica lagging) until it happens for real in production.
Real‑World & Industry Examples
Every major platform you use runs on a sharded system somewhere. Here is how six of them made the trade‑offs in real production.
Postgres, sharded by user ID
Custom‑generated IDs encode the shard number directly inside the ID itself, so the router can decode the shard without an extra lookup.
Schemaless on MySQL
Uses sharded data stores partitioned by identifiers like trip ID or city, allowing rides in different cities to be processed independently.
Sharded by channel ID
Message storage (originally MongoDB, later Cassandra and ScyllaDB) is sharded by channel ID, so each chat channel’s history lives together for fast retrieval.
Vitess for MySQL
Built Vitess to shard its massive MySQL‑based metadata store, later open‑sourcing it; Vitess is now widely used across the industry.
DynamoDB
DynamoDB, originally built to solve Amazon’s own shopping‑cart scaling problems, automatically partitions tables and is now offered as a managed AWS service used by thousands of companies.
Sharded by workspace
Shards workspace data so each workspace’s messages and files stay grouped together, keeping most queries within a single shard.
In system design interviews, being able to name a concrete shard key for a given system (“I would shard by restaurant_id for a food‑delivery app, since most queries are scoped to one restaurant’s menu and orders”) demonstrates much deeper understanding than simply saying “we would shard the database.”
Frequently Asked Questions
Ten of the questions candidates and engineers ask most often about sharding — answered without hand‑waving.
Sharding is a specific type of partitioning — namely, horizontal partitioning where the pieces are stored on separate physical database servers. “Partitioning” is the broader term and can also refer to splitting data within a single server (for example, PostgreSQL table partitioning).
Almost certainly not. A single well‑tuned database, possibly with read replicas and caching, can handle a surprisingly large amount of traffic — often millions of rows and thousands of requests per second. Sharding should be introduced only once you have clear, measured evidence that a single database can no longer keep up.
Traditional SQL JOINs generally cannot span multiple shards efficiently. Applications either avoid the need for cross‑shard joins by choosing a good shard key, duplicate (denormalise) some data, or perform the “join” manually in application code by querying multiple shards and combining the results.
Transactions within a single shard can remain fully ACID. Transactions across multiple shards are much harder and typically require distributed transaction protocols (like two‑phase commit) or the Saga pattern, both of which add complexity and latency — which is exactly why systems try to minimise the need for cross‑shard transactions.
Federation splits a database by function (e.g. a separate database for “users,” another for “orders,” another for “payments”), while sharding splits a single table’s rows across multiple servers. The two techniques are often combined: a large system might federate by function first, then shard each function’s database further as it grows.
A common practice is to start with more logical shards than physical servers — for example, 4,096 logical shards mapped onto just a handful of physical machines initially. As traffic grows, logical shards can be moved onto new physical machines without changing the shard key logic, because the total number of logical shards never has to change.
No. Sharding spreads data out but does not, by itself, protect against data loss. Regular backups and replication remain essential, since losing a shard without a backup or replica still permanently loses that portion of the data.
Resharding is the act of changing how data is distributed across shards — for example, going from 8 shards to 16, or moving a specific customer’s data from one shard to another because it grew too large. It is risky because the system must keep serving live reads and writes throughout the move, and any bug in the migration logic can silently corrupt or duplicate data. This is why mature systems use the dual‑write, backfill, verify, and cutover pattern described earlier, along with extensive automated verification before deleting the old copy of the data.
Federation and microservices both split data by subject area — one database for the orders service, another for the payments service, another for the inventory service. Sharding splits data within one subject area by rows. A large microservices architecture often uses both: each microservice owns its own database (federation), and if that individual database still grows too large, it gets sharded internally.
Auto‑sharding refers to a database automatically deciding when and how to split and rebalance data, without a human manually choosing shard boundaries. Databases like MongoDB, DynamoDB, Cosmos DB, and Google Spanner all offer this. For most teams, trusting a mature, widely‑used auto‑sharding system is safer and far less work than building custom sharding logic by hand — custom sharding is usually only justified at the scale of a company like Facebook, Google, or Uber, which have unique requirements that off‑the‑shelf systems cannot meet.
Summary & Key Takeaways
Sharding is the technique of splitting a large dataset by rows across multiple independent database servers, so that no single machine has to store or process all the data alone. It is one of the foundational tools for scaling from thousands to billions of records.
Sharding is the technique of splitting a large dataset by rows across multiple independent database servers, so that no single machine has to store or process all the data alone. It is one of the foundational tools for building systems that can grow from thousands to billions of records without hitting a hard capacity wall.
Remember This
- Sharding = horizontal partitioning of data across multiple database servers.
- The shard key is the most important design decision — it should have high cardinality, even distribution, and match common query patterns.
- Hash‑based, range‑based, and directory‑based are the three core sharding strategies, each with different trade‑offs.
- Consistent hashing dramatically reduces the amount of data that must move when shards are added or removed.
- Sharding is not the same as replication — production systems typically use both together, for scale and reliability.
- Cross‑shard queries (scatter‑gather) are slower and more complex, so good shard key selection minimises how often they are needed.
- The CAP theorem forces a practical choice between consistency and availability during network partitions.
- Sharding adds real operational complexity — it should be adopted only once simpler scaling techniques are no longer sufficient.
- Modern managed databases (DynamoDB, Cosmos DB, Spanner, MongoDB Atlas) handle much of the hard work of sharding automatically.
Understanding sharding well means understanding both sides of it: the elegant idea of splitting data to scale, and the very real engineering costs — complexity, cross‑shard queries, and rebalancing — that come with it. Every experienced architect learns to ask not “should we shard?” but “do we actually need to shard yet, and if so, what shard key will serve us for years, not just months?”