System Design interview questions: Sharding
Reviewed by Mark Dickie · Last updated
6 questions on this page you can answer and see marked on the spot. Go to the first one
Sharding is a horizontal partitioning technique that splits a large dataset across multiple database servers so each node holds only a subset of the rows. For interview purposes, you need to know the main sharding strategies (hash-based, range-based, directory-based, geo-based), the problems each one solves, and the trade-offs you inherit the moment you shard: cross-shard joins, distributed transactions, hotspot keys, and the cost of rebalancing when the cluster grows. Expect to explain when sharding is justified versus cheaper alternatives like read replicas, vertical scaling, or partitioning within a single node.
Most system design interviews that touch sharding follow the same arc: pick a partition key, justify it, describe how data is placed, then handle the operational consequences.
| Concept | What to know |
|---|---|
| Hash-based sharding | Apply a hash function to the partition key and mod by shard count. Distributes writes evenly but makes range scans hard and requires resharding when shard count changes. |
| Consistent hashing | Places shards on a hash ring so adding or removing a node moves only a fraction of keys. Reduces data movement during rebalancing compared to naive mod-N hashing. |
| Range-based sharding | Assign key ranges to shards (e.g. shard 1 owns IDs 0–9999). Good for range queries but prone to hotspots if traffic concentrates on one range. |
| Directory-based sharding | A lookup service maps each key to its shard. Flexible and reassignable, but the directory itself becomes a bottleneck and a single point of failure. |
| Geo-based sharding | Partition by region or location so user data stays close to the user. Common for global applications; complicates cross-region queries and consistency. |
What does a sharding interview question typically test?
- Choosing a partition key that avoids hotspots and keeps related data colocated.
- Explaining why a naive
key % Napproach breaks when you add a shard and how consistent hashing fixes it. - Handling cross-shard queries and distributed joins when a single user's data spans multiple shards.
- Describing the rebalancing process: how to split a shard, move data with minimal downtime, and route traffic during migration.
- Knowing when not to shard: if read replicas or vertical scaling solve the bottleneck, sharding adds complexity you may not need.
How do you pick a good shard key?
The shard key determines data distribution and query locality. A key with high cardinality and even write distribution (like a user UUID) spreads load well but scatters a single user's orders across shards if you shard on order_id. Sharding on user_id keeps a user's data together but can create a hotspot if one user generates disproportionate traffic. The interview answer is usually: pick a key that matches your dominant access pattern, has enough cardinality to distribute evenly, and avoids monotonically increasing values unless you pre-split ranges.
Key facts
- Tarmac has 21 System Design interview questions on this topic, 10 of them on this page, at difficulty 1–5 of 5.
- Tarmac tracked 3,204 job postings asking for System Design in October 2026.
- Roles asking for System Design advertise a median base salary of £87,500, across 827 job postings as of October 2026.
- Tarmac last reviewed these System Design interview questions on 21 September 2026.
At a glance
| Questions | 10 shown · 21 in the bank |
|---|---|
| Difficulty | 1–5 of 5 |
| Formats | Multiple answer, Ordering, Fill in the blank, Multiple choice, Short answer, Design exercise, True / false, Flashcard |
What you'll review
- sharding
- id generation
- resharding
Practice questions
Try one before you open the answer. Pick an option and press Check; it's marked on the spot.
Select ALL statements that are true about database sharding.#
Options
Pick every one that applies.
Show answer
Sharding splits one dataset across multiple database instances, with a shard key determining where each row lives. Hashing that shard key spreads writes more evenly than a steadily increasing key under range partitioning, which sends new writes to a single shard. Hash placement scatters consecutive keys, so range scans and cross-shard joins become more expensive.
Sharding divides one logical dataset across several database instances, with the shard key deciding which instance holds each row. Hashing the shard key scatters values, so a steadily increasing key like a timestamp or auto-increment ID no longer sends every new write to the same shard as it would under range partitioning. The two false statements are the reverse of how hashing behaves: hash placement breaks up consecutive keys, so range scans fan out across shards, and cross-shard joins require extra network round trips and coordination, making them costlier than single-shard joins.
A range-sharded key-value store has a router in front of several shards. The router holds a shard map that assigns key ranges to shards. Put the steps the router performs for a single-key read request in the order they happen, from the moment the request arrives until the client receives its response.#
Put these in order
Show answer
In a range-sharded system, a single-key read is handled by first extracting the key, then looking up the owning range in the shard map, forwarding the request to that shard, having the shard execute the read locally, and finally returning the result to the client. Each step depends on the output of the previous one, so the order is fixed.
The router cannot pick a destination until it knows the key, so it must first extract the key from the request. With the key in hand, it consults the shard map to find the shard whose range contains that key. Only then can it forward the request to that shard, which executes the read against its local data. The router can return the result to the client only after the shard has produced it. Each step consumes the output of the one before it, so this sequence is the only valid order.
A events table is range-sharded by its created_at timestamp, so each shard owns a contiguous time window. Every new insert carries the current timestamp, so all new writes land on the one shard that owns the most recent window. This creates a write _____ on that shard while the older shards sit mostly idle. Switching the shard key to a hash of a high-cardinality column spreads these writes across all shards, at the cost of efficient range scans over created_at.#
Show answer
A events table is range-sharded by its created_at timestamp, so each shard owns a contiguous time window. Every new insert carries the current timestamp, so all new writes land on the one shard that owns the most recent window. This creates a write hotspot on that shard while the older shards sit mostly idle. Switching the shard key to a hash of a high-cardinality column spreads these writes across all shards, at the cost of efficient range scans over created_at.
With range-based sharding on a monotonically increasing key such as a timestamp, every new row falls into the newest key range, so one shard receives essentially all inserts while the others handle little write traffic. This concentrated load is called a hotspot (or hot shard). Hash-based sharding distributes keys pseudo-randomly across shards, removing the write concentration but making range queries on the original column scatter across shards.
You are sharding a high-write events table across many partitions. Using created_at (a monotonically increasing timestamp) as the shard key causes one shard to absorb nearly all writes. What is the best remedy?#
Options
Show answer
Shard on a high-cardinality key, such as a hash of the tenant or entity id, so writes spread evenly across partitions. A monotonic timestamp routes every current write to whichever shard owns the latest range, creating a hot partition no matter how many shards exist. Adding replicas or vertically scaling the busy shard only raises one box's ceiling; neither balances the write distribution.
A monotonic timestamp routes all current writes to whichever shard owns the latest range, creating a hot partition no matter how many shards exist. Choosing a high-cardinality key (a hash of tenant or entity id) distributes writes uniformly, which is the actual fix. Adding replicas helps read load but not the write hotspot — replicas still funnel writes through one leader. Raising the shard count without changing the key leaves the newest range concentrated on a single shard. Vertically scaling the hot shard only raises its ceiling and reintroduces a single point of contention; it does not balance the distribution.
You're sharding a table across many database nodes and need globally unique primary keys generated at high throughput without a per-insert coordination round-trip, and you'd like them to be roughly time-sortable for index locality. Which approach best fits?#
Options
Show answer
Use Snowflake-style ids that pack a timestamp, a node id, and a per-node sequence counter — coordination-free, unique, and naturally time-ordered. Every node mints ids locally with no round-trip, and the timestamp prefix gives the index locality you want. A central sequence reintroduces the coordination and single point of failure; UUIDv4 is coordination-free but fully random, so it scatters B-tree inserts; and hashing row contents lets identical rows collide.
Snowflake-style ids compose a millisecond timestamp + a per-node id + a per-node monotonic counter, so every node mints unique, roughly time-sortable ids locally with no coordination — exactly the stated requirements. A central auto-increment sequence each node calls before every insert is unique but reintroduces the coordination round-trip and a SPOF the question rules out. UUIDv4 is genuinely coordination-free and a valid choice, but its full randomness defeats the time-sortability/index-locality goal — that's the honest trade that makes it second-best here. Hashing the row's own column values into the id is broken for keys: two rows with identical values collide, so it cannot guarantee uniqueness.
One partition (key range) in your sharded cluster has become a hotspot, and you must rebalance its load across more nodes while serving live traffic. Which approaches genuinely help redistribute the hot partition with minimal disruption?#
Options
Pick every one that applies.
Show answer
The approaches that genuinely help are splitting the hot key range into smaller sub-ranges and migrating some while double-writing during cutover, using consistent hashing with virtual nodes so adding capacity remaps only a fraction of keys, and introducing a finer-grained or composite shard key so the concentrated key spreads across partitions. Taking the shard offline to dump and restore is downtime, and vertically scaling only the hot node never rebalances anything.
Online resharding is about moving load without a stop-the-world cutover. Range splitting with a double-write window lets you migrate a sub-range while both locations stay readable, then flip reads once backfill completes — the standard live-migration pattern. Consistent hashing with virtual nodes bounds the blast radius of adding a node to ~1/N of keys instead of a near-total remap, which is what makes scaling out incremental. A finer/composite shard key attacks the root cause when the heat comes from a concentrated key, fanning it across partitions. The wrong options fail the 'live traffic, minimal disruption' constraint: dumping and restoring offline is downtime, not minimal disruption; and vertically scaling only the hot node just raises one box's ceiling without rebalancing — the partition stays a single hotspot and a SPOF.
How would you choose a shard key, and what goes wrong with a bad one?#
Show answer
A good shard key has high cardinality and a roughly uniform access distribution so reads and writes spread evenly across shards, and it ideally matches your most common query so requests hit a single shard instead of scattering. A bad shard key creates a hotspot: a low-cardinality or monotonically increasing key (like an auto-increment id or a timestamp) sends most traffic to one shard, producing uneven load and a hot partition while others sit idle. It also forces expensive scatter-gather queries and painful resharding when one shard outgrows its capacity.
The shard key decides how rows map to partitions, so it governs load balance and query routing. Aim for high cardinality, even distribution, and alignment with your dominant access pattern (so common queries are single-shard). The classic mistake is a monotonic or low-cardinality key, which concentrates traffic into a hotspot, forces scatter-gather across all shards, and makes rebalancing expensive — composite or hash-based keys often mitigate this.
Design a URL shortener (think Bitly / TinyURL).#
Show answer
Requirements. Two operations dominate: create (write a mapping, optionally with a custom alias and expiry) and redirect (look up a code and 30x to the long URL). The system is overwhelmingly read-heavy (100:1), so the redirect path is what we optimise. I'd confirm: are custom aliases required (yes), do links expire (optional TTL), and how precise must click counts be (approximate/eventually-consistent is fine). I'd use a 302 (temporary) redirect so we keep serving redirects through our system and can still count clicks; a 301 would let browsers cache and bypass us.
Capacity. ~40 writes/sec average, ~200/sec peak; ~4K reads/sec average, ~20K peak. Storage: ~6B links over 5 years; at ~500 bytes/row (code, URL, metadata) that's ~3 TB — comfortably shardable. Keyspace: base62 with 7 characters gives 62⁷ ≈ 3.5×10¹² codes, far more than 6B, so 7 chars (often padded to a fixed length) is plenty. The hot working set (recently/ popularly accessed links) is a small fraction of 6B, so a cache of tens of GB covers the bulk of redirect traffic.
Data model. A single mapping table/collection keyed by the short code: code (PK) → long_url, created_at, expires_at, owner_id. Point lookups by primary key suit a key-value store (DynamoDB/Redis-backed) or a sharded relational table sharded by code. Click counts live separately — incrementing a counter on every redirect would put write load on the read path — so clicks are emitted as events and aggregated asynchronously.
Short-code generation. Generate a unique 64-bit id (a distributed counter handed out in ranges per server, or a Snowflake-style id) and base62-encode it to get the short code; this guarantees uniqueness with no collision checks and no hotspot from a single shared counter. Custom aliases are written directly with a uniqueness check and stored in the same table, reserving that code. (A hash-of-URL scheme is the alternative but needs collision handling and breaks idempotency for duplicate URLs.)
Read/write paths. Write: allocate id → base62 → insert mapping → return the short URL. Redirect: a load balancer / CDN fronts stateless app servers; the server does a cache-aside lookup (code → long_url) in Redis, falling back to the store on a miss and populating the cache, then returns a 302. This keeps p99 well under 100 ms for cache hits. Expiry is enforced by TTL on both the row and the cache entry. Each redirect fires a lightweight click event onto a queue (Kafka) that a consumer aggregates into per-link counts.
Bottleneck & scaling. The bottleneck is the redirect read path at peak. We scale it with cache layers (most reads never touch the store), read replicas, and sharding the mapping store by code so lookups stay single-shard. Id generation scales by handing each server an independent id range (or using Snowflake), avoiding a single global counter as a SPOF. At 10× traffic, the cache absorbs most of it; we add cache nodes and replicas and, if needed, push redirects further to the edge.
A URL shortener is the canonical warm-up design: it forces a clean separation of a heavily read-optimised redirect path from a comparatively rare write path. The two pivotal decisions are short-code generation (a base62-encoded distributed id avoids both collisions and the hotspot of a single shared counter) and caching (cache-aside on code→URL, fronted by a CDN/LB, is what meets the latency budget when reads outnumber writes 100:1). Click counting is deliberately moved off the redirect path and made asynchronous so analytics never slow a redirect. The dominant bottleneck is the redirect read path, scaled by caching, read replicas, and sharding the mapping store by code.
Sharding a database by a high-cardinality monotonically increasing key (e.g. auto-increment ID or timestamp) guarantees even write distribution across shards.#
Options
Show answer
False. Monotonically increasing keys concentrate all writes on the last shard — the one owning the current maximum range — the classic hotspot-shard problem, while other shards sit idle for writes. Even though such keys are high-cardinality, they are temporally correlated. Even write distribution needs a hash-based or consistent-hash key, or random keys like UUIDv4; timestamp-ordered ULIDs recreate the same hotspot.
Monotonically increasing keys concentrate all writes on the last shard — the one that owns the current maximum range. This is the classic hotspot shard problem: every new row lands on one node while all other shards sit idle for writes. The correct sharding strategy for write-heavy workloads is a hash-based or consistent-hash key that scatters new rows uniformly, at the cost of losing range-scan locality. Alternatively, prefix the key with a random bucket, or use random keys like UUIDv4 that have no temporal correlation. Note that timestamp-prefixed IDs such as ULIDs do not help here — because they are monotonically increasing they recreate the same last-shard hotspot.
What problem does consistent hashing solve when sharding data across nodes, and how do virtual nodes help?#
Show answer
Naive sharding with hash(key) % N remaps almost every key when N changes, forcing a massive reshuffle whenever you add or remove a node. Consistent hashing places nodes and keys on a hash ring so that adding/removing a node only moves the keys in one adjacent arc — roughly 1/N of the data — rather than nearly all of it. Virtual nodes (many ring positions per physical node) smooth out the uneven key distribution and let you weight heterogeneous machines, avoiding hot shards.
Consistent hashing is foundational to distributed caches and databases (Dynamo, Cassandra, memcached clients) precisely because it minimises rebalancing churn during scaling and failure events. Without virtual nodes a small ring produces lopsided load; with them, distribution converges to near-uniform.
Related interview questions
Job market
See system-design salaries and hiring demand from live job postings.
The other 11 questions
This page shows 10 and marks what you pick. That's as far as a page can go. A free account opens the other 11 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.
Free · the whole bank · 100 answers per 30 days, each marked with written feedback