Why Everyone Asks This Question
"Design a URL shortener" (like Bitly or TinyURL) is one of the most common system design interview questions. It looks tiny: turn a long link into sho.rt/aB3x9Kq. But it touches everything interviewers care about: capacity estimates, unique ID generation, database choice, caching and trade-offs.
This guide walks through it the way you'd answer in an interview, step by step.
๐ฏ Quick Answer (30-Second Read)
- Two APIs: create a short link (write) and redirect (read). Reads dominate, often 100:1.
- Short code = base62 (aโz, AโZ, 0โ9). 7 characters give 62โท โ 3.5 trillion codes.
- Generate codes from unique IDs (a counter or ID ranges per server) encoded in base62, instead of hashing and checking for collisions.
- Store code โ long URL in a key-value friendly database. Cache popular codes in Redis.
- Redirect with 302 if you need click analytics; 301 lets browsers cache it.
Step 1: Requirements
Shorten a URL. Redirect a short URL to the original. Optional: custom aliases, expiry, click analytics.
Redirects must be very fast and highly available. Codes must be unique and hard to guess. Links shouldn't break for years.
Step 2: Capacity Estimates
Interviewers want to see you reason with numbers. Assume:
| Assumption | Value |
|---|---|
| New links per month | 100 million |
| Read:write ratio | 100:1 |
| Keep links for | 5 years |
| Size per record | ~500 bytes |
The math:
- Writes: 100M / (30 ร 24 ร 3600 s) โ 40 per second
- Reads: 40 ร 100 โ 4,000 redirects per second (plan for peaks several times higher)
- Total links: 100M ร 12 ร 5 = 6 billion
- Storage: 6B ร 500 bytes โ 3 TB
Conclusion: storage is modest, writes are light, and the system is read-heavy. That points to caching as the main performance lever.
Step 3: How Long Should the Code Be?
With base62, each character has 62 options:
| Length | Possible codes |
|---|---|
| 6 | 62โถ โ 56.8 billion |
| 7 | 62โท โ 3.52 trillion |
| 8 | 62โธ โ 218 trillion |
6 billion links fit in 6 characters, but 7 leaves huge headroom and makes codes harder to guess.
Step 4: Generating Unique Codes
Take MD5/SHA of the URL, keep the first 7 base62 characters. Simple, but collisions are possible, so every write must check the database and retry.
Give each link a unique number, then encode it in base62. No collisions by design. The challenge is generating unique numbers across servers.
Making counters work at scale: a central ID service hands each app server a range (server 1 gets 1โ1,000,000, server 2 gets 1,000,001โ2,000,000). Servers assign IDs from their range in memory and only ask for a new range when it runs out. Ranges can be coordinated with a database sequence or a tool like ZooKeeper.
ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base62(n: int) -> str:
code = ""
while n:
n, r = divmod(n, 62)
code = ALPHABET[r] + code
return code or "0"
print(to_base62(125_000_000_000)) # โ '2crtgcg' (7 characters)Step 5: Architecture
hot codes")] C -.->|"miss"| DB[("Database
code โ long URL")] API --> DB API -->|"click event"| Q[["Queue"]] Q --> AN["Analytics workers"] --> AW[("Analytics store")]
Redirect flow:
Step 6: Database Choice
The core data is a simple key โ value lookup with no joins: code โ long_url, created_at, expires_at, user_id.
- Key-value / wide-column stores (DynamoDB, Cassandra) scale this pattern easily.
- Postgres or MySQL also work well at this size (3 TB) with an index on the code, plus read replicas or sharding by code later.
Either is defensible in an interview. Explain your reasoning.
Step 7: 301 vs 302 Redirects
| 301 Moved Permanently | 302 Found (temporary) | |
|---|---|---|
| Browser caching | Browser may remember and skip your server next time | Browser asks your server every time |
| Server load | Lower | Higher |
| Analytics | Miss repeat clicks | Count every click |
| Change destination later | Hard | Easy |
Services that sell analytics usually use 302 (or 307).
Extras Interviewers Like
- Custom aliases: check availability, reserve in the same table
- Expiry: store
expires_at, check on redirect, clean up in the background - Abuse: rate-limit creation, scan destinations for malware or phishing
- Analytics: send click events to a queue so redirects stay fast
- Availability: replicate the database and run servers in multiple zones
Frequently Asked Questions
How does a URL shortener generate unique codes?
The most robust approach assigns each link a unique number, often from ID ranges handed to each server, and encodes it in base62 using letters and digits. Hashing the URL also works but requires collision checks. Seven base62 characters give about 3.5 trillion possible codes.
Should a URL shortener use 301 or 302?
A 301 redirect lets browsers cache the destination, reducing load but hiding repeat clicks. A 302 redirect sends every click through your server, which enables accurate analytics and changing destinations later. Most commercial shorteners use 302 or 307 for that reason.
How do you scale a URL shortener?
Because it is read-heavy, cache popular codes in memory with Redis, serve redirects from stateless app servers behind a load balancer, replicate or shard the database by short code, and push analytics events to a queue so they don't slow redirects.
Conclusion
A URL shortener is small but complete: estimate capacity, choose base62 codes of the right length, generate them from unique IDs, store a simple key-value mapping, cache aggressively for a read-heavy workload, and pick 301 or 302 based on whether you need analytics. Explaining those trade-offs is exactly what interviewers want to hear.
Sources
Last verified: 14 October 2026.
Related reads: Rate Limiter Explained ยท Consistent Hashing Explained ยท Redis Explained ยท Instagram System Design
I write about system design and how real products are built. Follow on LinkedIn or X, or invite me to speak.