#1. Introduction
A URL shortener is easy to build until a redirect has to work in milliseconds, across regions, while links expire, destinations change, and bots try to turn your domain into a spam service. The central design challenge is managing a heavily read path without letting caches, analytics, or abuse controls make it unreliable.
This design treats a short link as a globally readable mapping, with creation and analytics handled separately from the redirect path. The numbers below are working assumptions for a design exercise, not claims about a particular service.
#2. Problem statement and requirements
A user submits a long URL and gets back a short code, such as aB7xQ2. When someone visits sho.rt/aB7xQ2, the service looks up the destination and redirects the browser.
#Functional requirements
- Create a short link for a valid destination URL.
- Redirect a short code to its destination.
- Support optional expiration and, if required, destination updates.
- Record redirect events for analytics.
- Reject invalid or unsafe destinations, and let operators disable abusive links.
#Non-functional requirements
For a concrete sizing exercise, assume:
- 100 million new links per day.
- 10 billion redirects per day, making reads the dominant workload.
- A 500,000 redirects per second peak across all regions.
- Redirect lookup should usually complete within tens of milliseconds.
- A link should remain available through an individual cache, database replica, or application instance failure.
At 10 billion redirects a day, the average is about 116,000 requests per second. A peak of 500,000 is a planning assumption; real traffic can be uneven, and a single popular link can account for a large share of requests.
The design prioritizes availability and latency for redirects. Creation can tolerate a little more latency, while analytics may be delayed because a chart that updates a few seconds later is preferable to a redirect that waits on an analytics database.
#High-level architecture
flowchart LR
A["Browser or API client"] --> B["Global load balancer"]
B --> C["Regional redirect service"]
C --> D["Local cache"]
D --> E["Regional mapping cache"]
E --> F["Mapping database"]
C --> G["Event queue"]
G --> H["Analytics consumers"]
H --> I["Analytics store"]
J["Create API"] --> K["Input validation and abuse checks"]
K --> L["Short-code generator"]
L --> M["Mapping database"]
N["Admin service"] --> M
N --> E
The redirect service checks local caches before querying the mapping database. It publishes an event for analytics without waiting for that event to be processed. The create API validates the destination and writes the mapping; an admin service can disable a link and trigger cache updates.
#Data model
A mapping record can be stored in a key-value database partitioned by short code:
{
"code": "aB7xQ2",
"destination": "https://example.com/article",
"created_at": "2026-11-05T12:00:00Z",
"expires_at": null,
"status": "active",
"redirect_type": 302,
"owner_id": "user-123",
"version": 1
}
The primary lookup is code → mapping. This is a good fit for a key-value access pattern: redirects need one record by code, not a scan or join.
Keep high-volume click events out of the mapping table. An event can include the code, timestamp, region, and limited request metadata. Avoid collecting full IP addresses or user-agent strings by default; they can create privacy and retention costs, and most product analytics don’t need them.
Expiration needs two checks. A background process can delete expired records eventually, but the redirect handler must compare expires_at with the current time itself. Database TTL cleanup is asynchronous, so it cannot be the authority for whether a link is valid.
#Key components
#Short-code generation
A random Base62 code uses 62 possible characters: uppercase letters, lowercase letters, and digits. A code of a chosen length gives a large namespace, but random generation still has a collision chance.
Use a cryptographically secure random generator, then insert the record with a conditional write that succeeds only if the code is unused. If it collides, generate another code and retry. The conditional write is the correctness mechanism; estimating that collisions are unlikely is not a substitute.
A sequential counter encoded as Base62 is another option. It guarantees uniqueness if allocation is correct, but introduces coordination, predictable codes, and potential hot spots. Random codes are usually simpler to distribute. Neither approach makes codes secret: access control must be separate from an unguessable URL.
#Redirect service
The redirect path should do as little work as possible:
- Parse and validate the requested code.
- Check the local cache.
- On a miss, read the mapping from the regional cache or database.
- Reject missing, expired, or disabled mappings.
- Return a redirect and publish an analytics event asynchronously.
A redirect status code affects behavior. A 302 is a reasonable default when the destination may change or the service needs flexibility. A 301 can be cached by browsers and intermediaries, which may reduce load but make destination changes harder to apply. Pick deliberately and document what users should expect.
#Cache and invalidation
Use a short-lived in-process cache for the hottest mappings and a distributed regional cache for the wider working set. Cache negative lookups too, with a short expiry, so repeated requests for invented codes don’t hammer storage.
Cached data creates a consistency choice. If destinations are editable, an update must invalidate or refresh cached entries, and stale copies may still be served briefly. A version field helps consumers detect updates, but it doesn’t invalidate a cache by itself. For immediate link takedowns, use a denylist or revocation check that the redirect service can consult quickly.
#Analytics pipeline
The redirect handler should enqueue a small event and return without waiting for aggregation. Consumers can group events by code and time window, then write summaries to an analytics store suited to reporting queries.
This separates two different workloads: mapping lookups need low-latency access by code; analytics needs aggregation across many events. If the queue is unavailable, decide whether to drop events, buffer locally, or return an error. For most shortening services, redirects should continue and analytics can be incomplete during an outage.
#Scaling & bottlenecks
#Hot links
A popular link can overwhelm a single cache shard or database partition even when overall traffic is healthy. Replicate hot mappings across cache nodes, use local caches to absorb repeat requests, and avoid routing every cache miss to one storage node.
Track per-code traffic and cache hit rates. Global averages can hide a single viral link that dominates one region.
#Multi-region reads
Place redirect services and caches near users, and replicate mapping data to the regions that serve traffic. Random codes make independent code allocation practical, but they don’t solve replication consistency.
A newly created mapping may reach another region after a delay. Options include routing creation to a home region and waiting for replication before returning success, or briefly routing misses to the authoritative region. The first adds creation latency; the second adds complexity to the miss path. Choose based on how quickly a new link must work worldwide.
#Database capacity
The database sees far fewer requests than the raw redirect count if caches are effective, but cache misses still need predictable handling. Monitor hit rates, read latency, throttling, and the distribution of requests across partitions. A cache outage can turn a comfortable database load into a sudden surge, so capacity and load shedding should account for cache failure.
#Abuse and availability
Shorteners attract phishing, malware, spam, and automated code guessing. Validate URL schemes, block destinations against threat feeds, apply creation and lookup rate limits, and provide a fast disable path for reported links.
Rate limiting only at the application layer can be bypassed by spreading requests across IP addresses. Use several signals, such as account, network, and request pattern, while avoiding a design that blocks legitimate users behind shared networks. Also protect the redirect domain’s reputation: one abusive tenant can affect every customer using it.
#Trade-offs
| Choice | Benefit | Cost |
|---|---|---|
| Random codes | Easy to distribute; less predictable | Must handle collisions |
| Sequential codes | Simple uniqueness; compact allocation | Coordination and enumeration risk |
| Long cache TTL | Fewer storage reads | Slower updates and revocation |
| Short cache TTL | Fresher mappings | More cache misses and database load |
| Synchronous analytics | Events are easier to confirm | Adds latency and failure coupling |
| Asynchronous analytics | Keeps redirects fast | Reports can be delayed or incomplete |
There’s no single “correct” cache lifetime or redirect status code. The right choice depends on whether links are editable, how quickly takedowns must propagate, and whether browser caching is acceptable. Make those product requirements explicit before tuning infrastructure.
#Interview tips
Start by clarifying what “scale” means: daily link creation, peak redirect rate, geographic distribution, expiration, custom aliases, and whether destination updates must take effect immediately. Then estimate read-to-write ratio and identify the hot-key problem.
A strong interview answer explains the redirect path before listing services. Show how a request moves through caches and storage, how an expired link is handled, and what happens when the cache or analytics queue fails. Close with the consistency boundary: which operations must be immediate, and which can be eventually consistent?
Challenge: Design a takedown path
A mapping is reported as malicious, but its destination is cached in several regions. Design a mechanism that stops new redirects quickly without making every redirect depend on a central database.
Show solution
Keep a replicated revocation set that redirect services check before returning a cached mapping. Propagate updates through an event stream, and use short cache lifetimes as a fallback. The trade-off is added read-path work and the need to define behavior if revocation data is stale or unavailable.
#Key takeaways
- Design the redirect path for reads first; creation and analytics have different latency needs.
- Use conditional writes to guarantee unique codes, even when collisions are unlikely.
- Treat cache invalidation, expiration, and malicious-link takedowns as correctness problems.
- Keep analytics asynchronous so its availability doesn’t determine whether redirects work.
- Plan for hot links and cache failure, not only average traffic.

Comments
No comments yet. Start the conversation.