SYSTEM DESIGN · QUESTION 11
How would you design a URL-shortening service?
On this page
I would separate the write path that creates a short code from the read-heavy redirect path. The API validates the destination, generates a unique code, and stores the mapping with expiry and ownership metadata. Redirects use a cache in front of durable storage, with careful handling for missing or expired codes. I would clarify traffic and reliability requirements first, then address abuse controls, analytics, and cache consistency.
LET'S MAKE IT SIMPLE
First, the idea in plain English
A URL shortener stores a mapping between a compact code and a longer destination. Creating a link writes that mapping; opening it performs a lookup and redirects the browser. The service is often read-heavy, because each created link may be opened many times. That makes fast lookup and availability important, while code uniqueness, abuse prevention, and link expiry shape the write and storage design.
A USEFUL COMPARISON
Picture it this way
It is like a coat-check ticket: a short number points to a larger item stored elsewhere. The analogy captures lookup, but the service must also handle concurrent code creation, malicious destinations, expiration, and a very large number of reads.
FOLLOW THE JOURNEY
A redirect is a lookup followed by an HTTP response
Trace both code creation and the high-volume redirect path through the service.
Cache misses read durable storage. The diagram omits optional analytics, regional routing, and abuse-review services; requirements determine whether to add them.
A client creates a short URL through an API and stores a code mapping; visitors request the code, check cache, fall back to mapping storage, then receive a redirect.
How to read this visual
Cache misses read durable storage. The diagram omits optional analytics, regional routing, and abuse-review services; requirements determine whether to add them.
UNDER THE HOOD
How it works, step by step
Clarify requirements
Ask about traffic, custom aliases, expiry, analytics, availability, and abuse constraints.
Why it matters: These choices change storage, caching, and operational needs.
Create a mapping
Validate the destination, allocate a unique code, and persist the mapping.
Why it matters: The code must not collide with another active mapping.
Serve redirects
Read cache first, fall back to the database, and return a redirect or an appropriate error.
Why it matters: This path is usually the latency-sensitive read path.
Scale and protect
Partition by code, replicate reads, cache hot mappings, and rate-limit creation.
Why it matters: Traffic skew and abuse can dominate normal operation.
Observe and recover
Track lookup misses, latency, storage health, and abuse signals.
Why it matters: Failures and malicious use need visible response paths.
OUTSIDE THE TEXTBOOK
A practical example
A user submits a long destination. The service normalizes and validates the URL, generates a random code, checks uniqueness, and stores it. A visitor opens the short link; the service checks cache, loads the mapping on a miss, caches it, and returns a redirect. Expired codes return a defined unavailable response rather than redirecting to stale data.
GO A LITTLE DEEPER
Technical details that matter
- Illustrative assumptions to confirm: redirects outnumber link creation and short codes remain unique while active. No numeric traffic target is given here; ask about read/write volume, latency, expiry, and availability before sizing.
- At high scale, random codes need enough entropy to keep collision probability low; collision checks or database uniqueness constraints must still enforce correctness.
- A base-N encoding of an allocated numeric ID avoids random collisions but may expose creation order and requires an ID-generation strategy.
- Cache-aside is simple for redirects but invalidation and expiry behavior must match the mapping’s lifecycle.
- The HTTP redirect status affects caching and whether clients may retain the destination; choose according to mutability and product requirements.
POST /v1/links
{ "url": "https://example.com/article", "expiresAt": null }
201 Created
{ "shortUrl": "https://mp.example/aB31x" }
GET /aB31x → 302 Location: https://example.com/articleThis simplified API illustrates the create and redirect flows, not a full implementation. The actual service also needs authentication or abuse controls as appropriate, validation, unique code allocation, and an error contract.
MAKE A GOOD CHOICE
When is this useful?
- Redirects with stable mappings and high read volume.
- Links that benefit from controlled expiry, ownership, or measured usage.
- Campaign links where a service needs to manage destination mappings.
If the requirement is only to store and display links for a small private app, a dedicated shortener may be unnecessary. A static mapping or existing trusted service could be simpler.
WATCH OUT FOR
Common misunderstandings
- Assuming a cache alone guarantees availability or correctness.
- Ignoring destination validation and phishing or malware abuse.
- Generating codes without enforcing uniqueness under concurrent writes.
REAL-WORLD TRADE-OFFS
Limitations and failure cases
- A hot link can create cache or regional hotspots.
- Redirects add a dependency and can become an availability bottleneck.
- Analytics and previews can introduce privacy, latency, and crawler-behavior concerns.
WHAT TO REMEMBER
Key takeaways
- 1Separate creation from the read-heavy redirect path.
- 2Enforce uniqueness in durable storage, not only in application logic.
- 3Use caching deliberately with expiry and invalidation behavior.
- 4Clarify product, reliability, and abuse requirements before choosing details.
PRACTICE THE FOLLOW-UP
What might an interviewer ask next?
How would you generate short codes?
Possible approaches include random codes with uniqueness checks or encoding allocated IDs. The trade-off includes collision handling, predictability, and ID coordination.
How would you handle a popular short link?
Cache the mapping near users, monitor hot keys, and consider replication or request coalescing while preserving expiry and invalidation semantics.
How do you prevent malicious redirects?
Validate URL schemes, rate-limit creation, apply reputation or review controls appropriate to risk, and provide reporting and takedown processes.
SAY IT OUT LOUD
How to explain this in an interview
“I would first clarify scale, expiry, custom aliases, analytics, and availability targets. The design has a write path that validates a destination, allocates a unique code, and stores the mapping, plus a read-heavy redirect path that checks cache before durable storage. I would enforce uniqueness at the storage boundary and add rate limits and abuse controls. Cache behavior, redirect semantics, and analytics depend on the product requirements.”
Connect this question to the roadmap topic it supports.