Design a URL shortener
Design a URL shortening service like TinyURL: turn a long URL into a short alias, and redirect anyone who visits the alias to the original URL.
Practise it in the interview simulatorDraw your design on a canvas, stress test it with real traffic, and get a scored report. Or watch this answer build itself, step by step.1. Clarify the requirements
Before drawing anything, ask questions. These are the answers an interviewer would typically give:
- How many URLs?
- 100 million new short URLs per day.
- How short?
- As short as possible; characters 0-9, a-z, A-Z.
- How long are URLs kept?
- 10 years.
- Read/write ratio?
- 10 redirects for every new URL.
- Can URLs be deleted or edited?
- No, for simplicity.
- Analytics?
- Click analytics would be nice, so think about the redirect status code.
2. Estimate the scale
Assumptions: 100M new URLs per day, 10:1 read/write, kept for 10 years, ~100 bytes per record.
- Write QPS: about 1160 writes/s100M ÷ 86,400 ≈ 1,160/s.
- Redirect QPS: about 12K reads/s10 × 1,160 = 11,600/s.
- Records in 10 years: about 365B records100M × 365 × 10 = 365 billion.
- Storage for 10 years: about 36.5 TB365B × 100 bytes = 36.5 TB.
3. The high-level design
- Users reach a stateless URL serviceA load balancer spreads requests over stateless servers. Shortening and redirecting are both simple lookups, so the service scales by adding servers.
- Store short → long mappingsBillions of tiny records read by key: a key-value store sharded by short code, with three replicas, fits perfectly.
- Cache the hot linksRedirects outnumber new links 10 to 1, and a few links get most clicks. An in-memory cache answers them without touching the database.
- Unique IDs without collisionsA Snowflake-style ID generator hands out unique, time-ordered IDs; base62-encoding one gives the short code, so there's no hash collision to check.
- Watch it in productionMetrics and alerts close the loop: redirect p99, cache hit ratio and 4xx/5xx rates.
4. The components and what each one does
- Load balancer Load balancer
- Spreads requests over the stateless servers behind it, health-checks them and routes around a dead one. Rate limits abusive clients.
- URL service App servers
- Stateless. Shorten: new unique ID → base62 (7 characters, 62⁷ ≈ 3.5 trillion codes). Redirect: look up the long URL and answer 301 (cached by browsers) or 302 (every click counted). Rate limits link creation.
- URL store NoSQL / KV store · DynamoDB / Cassandra
- short code → long URL. Key-value, sharded by short code, 3 replicas with failover.
- Redirect cache Cache · Redis
- short code → long URL, LRU eviction. Hot links are served from memory.
- ID generator Service
- Snowflake-style unique IDs (timestamp + machine + sequence): no collisions, no coordination between servers.
- Metrics & alerts Metrics & alerts
- Dashboards and alerts on p99 latency, error rate, queue depth and cache hit ratio, so a bottleneck shows up before it becomes an outage.
5. Deep dive: generating short codes
How do you generate unique short codes? Compare hashing + collision checks with base62 encoding of a unique ID. How long must the code be?
- 62⁷ ≈ 3.5 trillion, enough for 365 billion URLs: 7 characters.
- Hash (CRC32/MD5) and take 7 chars → collisions → check DB (Bloom filter helps).
- Or: get a unique ID (Snowflake) and base62-encode it: no collisions, but codes are guessable.
6. What interviewers listen for
- Shorten and redirect APIsPOST /api/v1/data/shorten {longUrl} and GET /api/v1/{shortUrl}.
- 301 vs 302 redirect choice301 is cached by browsers (less load, no analytics); 302 hits you every time (analytics).
- Code length from the numbers (7 base62 chars)62⁷ ≈ 3.5 × 10¹² > 365 × 10⁹.
- A code generation strategyExplain exactly how a long URL becomes a short, unique code.
- Collisions handled (or avoided with unique IDs)Hashing collides; either check (Bloom filter) and retry, or use a unique ID generator.
- Database replication and failoverA single database is a single point of failure. Replicas give redundancy and read capacity; failover promotes a replica when the primary dies.
- Partition (shard) data as it growsOne machine eventually can't hold the data or the write load. Say how you'd split it and by which key.
7. Follow-up questions
- Security notices people can enumerate everyone's links by incrementing the code. Is that a problem in your design, and how would you fix it?
- Sequential IDs are guessable (base62 of a counter)
- Add randomness: random/hashed codes, or shuffle/encrypt IDs
- A short link is posted during the Super Bowl and gets 1M redirects a minute. What happens?
- Served from cache (or CDN/edge)
- 301 can offload repeated browser visits
- Rate limiting protects the service
- Marketing wants click counts per link per day. What do you change?
- Use 302 so every click reaches you
- Log clicks asynchronously (queue/stream) and aggregate
The design in a nutshell
- LB → stateless web servers. Shorten: get a unique ID (Snowflake), base62-encode it (7 chars), store (id, shortURL, longURL) in a sharded KV/DB; return 7-char code.
- Redirect: look up cache → DB on miss → 301 (or 302 for analytics).
- Cache hot mappings; rate-limit shortening; replicate the store; Bloom filter if using hashing.
Related lessons: How long should the short code be? · Approach 1: Hash + collision resolution · Approach 2: Base-62 conversion ✅