System Design Case Studies
Designing a URL Shortener
The "hello world" of system design — deceptively simple until you hit the two real problems: generating short, collision-free codes at scale, and serving redirects fast enough that latency is invisible.
- Core requirement: given a long URL, return a short code; given the short code, redirect (HTTP 301/302) to the original URL
- Anchor the design in numbers: e.g. 100M new URLs/month at a 100:1 read:write ratio — redirects, not creation, are the hot path
- Short code generation: base62-encode an auto-incrementing ID (simple, collision-free, but a bottleneck at one counter), a random code with a collision check, or pre-allocated key ranges handed to writer nodes
- The redirect path should be cacheable and fast — a cache or CDN in front of the database turns a hot lookup into a memory access
- A simple key-value store (short code to long URL) fits the access pattern exactly — no relational schema or joins needed
- Custom aliases, expiration, and click analytics change the write path (a uniqueness check for aliases) and add an async analytics pipeline that must stay off the redirect's critical path
| Strategy | Uniqueness guarantee | Write contention | Complexity |
|---|---|---|---|
| Base62(auto-increment ID) | guaranteed by the counter | single counter is a bottleneck | low |
| Random + collision check | checked per write | a retry loop on collision | medium |
| Pre-allocated key ranges | guaranteed — ranges never overlap | none — each writer owns a range | medium-high |
static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static String encode(long id) {
StringBuilder sb = new StringBuilder();
while (id > 0) {
sb.append(ALPHABET.charAt((int) (id % 62)));
id /= 62;
}
return sb.reverse().toString();
}