Skip to content
Back to all concepts
System DesignDatabasesDistributed Systems

URL Shortener: Allocation, Redirects and Revocation

Design short-link allocation with collision handling, explicit redirect caching, safe revocation and realistic storage estimates.

By ScaleWikiUpdated 4 min readIntermediate

URL shorteners: uniqueness is a database decision

This exercise designs a short-link service with editable destinations, expiry, and usage counts. It does not describe Bitly or TinyURL's internal systems. The important boundary is between allocating a unique alias and deciding how long a browser or edge may remember its destination.

State the workload

Assume ten million stored links, one million new links per month, and 100 redirects per new link. In a 30-day month, those figures imply about 0.39 creations and 38.6 redirects per second on average. Test bursts and a single popular link separately; averages are poor predictors of a launch-day spike.

Suppose a link record averages 300 bytes including destination, alias, owner, timestamps, and flags. Ten million records occupy about 3 GB of logical data. Add indexes, replication, history, and engine overhead separately. Counting only URL bytes understates storage, while assuming every workload needs a distributed database overcomplicates the initial design.

Allocate a code atomically

Seven characters from a 62-symbol alphabet provide 62^7 = 3,521,614,606,208 possible codes. A cryptographically secure random generator can choose a candidate; a unique constraint on the alias decides whether it can be inserted. If the insert conflicts, choose another candidate and retry within a bounded budget.

With ten million occupied codes uniformly spread across that space, a new random candidate has about a 0.000284% chance of already being used. That small per-attempt probability does not mean collisions never happen over the service's lifetime. The database check is required.

An integer counter encoded in Base62 is another valid option. It provides compact unique codes while the allocator remains correct, but exposes ordering and makes enumeration easier. Distributed range allocation requires durable ownership of ranges and a plan for abandoned IDs after a crash. Gaps are usually acceptable for short links.

A pre-generated pool does not magically eliminate collisions: generation must ensure uniqueness and allocation must prevent two workers claiming the same code. Do not shorten a hexadecimal hash and call the result Base62; seven hex characters have only 16^7 possibilities.

One creation request, one result

The API accepts the destination and an optional requested alias. A unique alias constraint resolves concurrent claims. A client operation key can return the same result when a creation request is retried after an acknowledgment is lost.

Validate the destination as an absolute HTTP or HTTPS URL and reject unsupported schemes and embedded user credentials. Preserve meaningful path, query, and fragment components. Two URLs differing in case, query order, or a www host are not universally equivalent. If a preview service fetches destinations, it also needs protection against requests to internal addresses and redirect chains; redirecting a browser and fetching a URL on the server are different operations.

Redirect status and cache policy work together

HTTP defines 301 as permanent and 302 as temporary. A 301 can be heuristically cached; a 302 can also be cached when explicit freshness information permits it. “302 always reaches our server” is therefore not a valid analytics or revocation guarantee. HTTP Semantics, RFC 9110.

For this exercise, use a temporary redirect with Cache-Control: no-store for editable or revocable links. That gives up client-side caching to keep decisions at the service. If edge caching is introduced, define its maximum staleness and purge behavior explicitly. For a genuinely immutable public link, a permanent redirect with a deliberate freshness policy may be reasonable.

Usage counts are observations, not an exact count of human readers. Preview bots, retries, browser prefetches, and blockers affect them. Process analytics asynchronously with a bounded queue, so a metrics outage does not block a valid redirect.

Revocation is the hard cache case

Imagine a popular link is disabled at 14:00 while an edge has cached its redirect for an hour. Updating the database alone leaves the redirect usable there. A short TTL bounds the delay; purging can reduce it but needs delivery and confirmation. A permanently cached browser redirect may be beyond the service's immediate control.

Choose the product promise before the TTL. If immediate abuse takedown is essential, avoid long-lived client caching and check a current deny decision at the serving layer. Protect destination edits and takedown actions with authorization and an audit trail.

A practical test creates the same custom alias concurrently, retries a timed-out creation, expires a cached link, changes its destination, and disables it during a traffic burst. Check uniqueness and observed revocation delay. Those results determine whether a cache is acceptable and whether the service needs more capacity; an arbitrary technology list does not.