Designing a URL shortener system end-to-end
URL shortener architecture, base62 encoding, hash collision handling, redirect performance, read vs write path optimization, analytics counting, database choice
Designing a URL shortener system end-to-end
Requirements
Input: long URL. Output: 7-character short code. On GET /:code redirect to long URL. Scale: 100M URLs, 12,000 reads/sec, 1,200 writes/sec.
Generating Short Codes
Use base62 (a-z A-Z 0-9): 62^7 = 3.5 trillion combinations. Two approaches:
// Option 1: Hash URL, take first 7 chars — risk of collision
// Option 2: Auto-increment DB ID, encode to base62 (collision-free)
function toBase62(num) {
const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
let result = '';
while (num > 0) {
result = chars[num % 62] + result;
num = Math.floor(num / 62);
}
return result.padStart(7, '0');
}Auto-increment plus base62 is collision-free. Downside: sequential codes are guessable. Add a random shuffle if privacy is needed.
Read Path Optimization
Reads are 10x more frequent than writes. Cache short code to long URL in Redis with a 24-hour TTL. On cache hit return 301 (permanent redirect, browser caches it too — zero future server load for that user). On cache miss query DB and populate cache. Use 302 for analytics since it forces every redirect through the server to be counted.
