The URL shortener is one of the most common system design questions you'll get. It's popular because it's small enough to fit in 45 minutes but deep enough to separate someone who's memorized buzzwords from someone who actually thinks. I'll walk through how I'd approach it.
Start by clarifying
Don't jump to a diagram. The first thing I do is ask questions, because the interviewer almost never gives you the full picture up front.
- How many URLs do we create per day? How many redirects do we serve?
- How long do short links need to live? Forever, or do they expire?
- Do users get custom aliases, like
short.ly/my-launch? - Do we need analytics on clicks?
The answers change the design. For this walk-through, assume something modest but real: a few million new links a day and a read-heavy workload, since people click links far more than they create them. That read-heavy detail matters, so hold onto it.
The core operations
There are really only two things this system does.
- Take a long URL, return a short one.
- Take a short one, redirect to the long one.
Everything else is detail hanging off those two.
How short is the short URL
This is the part people fumble. You need a unique key for each link, and you want it short.
If you use the characters a-z, A-Z, and 0-9, that's 62 options per character. With a 7-character key you get 62^7, which is around 3.5 trillion combinations. That's plenty for years of growth. A 6-character key gives you about 56 billion, which may still be fine depending on the numbers you agreed on earlier. Tie the length back to the scale you clarified.
So the question becomes: how do you generate that key?
Generating the key
There are a few common approaches, and the interviewer wants to hear the tradeoffs, not one memorized answer.
Hash the URL. Run the long URL through something like MD5 or SHA-256 and take the first few characters. Simple, but you get collisions, and two different long URLs can land on the same short key. You'd need to check for collisions and retry, which adds reads.
Counter plus base-62 encoding. Keep a global counter. Each new link gets the next integer, and you encode that integer in base 62. No collisions by design, and the keys come out short. The catch is the counter is a single point of contention. You can solve that by handing each application server a range of IDs to burn through, so they don't fight over one counter on every write.
Random keys with a uniqueness check. Generate a random 7-character string, check the database, retry on the rare collision. At low fill rates collisions are rare enough that this is cheap and easy to reason about.
I usually lead with the counter approach and mention the others. It's clean, and the ID-range trick shows you've thought about contention.
Storage
The data model is almost embarrassingly simple. A table or key-value store mapping the short key to the long URL, plus a created timestamp and maybe an owner and an expiry.
The short key is your primary key. Reads are point lookups by key, which is exactly what a key-value store is good at. This is a reasonable place to reach for something like DynamoDB or a similar store rather than forcing a relational schema you don't need.
If you went with the counter approach, you also need somewhere durable to track ID ranges.
Serving redirects fast
Remember the read-heavy detail from the start? This is where it pays off.
Most lookups will hit the same popular links over and over. Put a cache in front of the database. When a redirect comes in, check the cache first, fall back to the store on a miss, then populate the cache. A least-recently-used eviction policy fits well, since hot links stay hot.
One small but real decision: do you return a 301 or a 302 redirect? A 301 is permanent and browsers cache it aggressively, which saves you traffic but means you lose visibility into clicks and can't easily change the destination. A 302 sends every click back through your service, which is what you want if analytics matter. Mentioning this tradeoff lands well, because it shows you're thinking about the product, not just the boxes.
Where to go deeper if there's time
If the conversation keeps going, good follow-ups to raise yourself:
- Analytics, by writing click events to a queue so you don't slow down the redirect path.
- Rate limiting to stop abuse and spam links.
- Custom aliases, which means checking a chosen key isn't already taken.
- Cleaning up expired links.
How to practice this
The trap with this question is treating it like trivia. The interviewer isn't grading whether you said the word "base62." They're watching how you move from vague requirements to concrete choices and whether you can name a tradeoff without being prompted.
The best prep is doing the walk-through out loud, ideally with someone pushing back. Run a couple of mock interviews on it, get used to clarifying before designing, and practice saying "it depends, here's on what" instead of guessing. Once you can talk through this one cleanly, a lot of the other design questions start to feel familiar.