Deep Dive
system design interviewdatabasescachingalgorithms

Design a URL Shortener

The canonical system-design interview, built end to end: how tiny.co/aB3xK9 becomes a database lookup in single-digit milliseconds — base62, key generation, the read-heavy cache, and the scale math that makes 7 characters last a century.

·20 min read
Medium

Every system-design interview starts here for a reason. A URL shortener looks trivial — map a long link to a short one — but the follow-up questions walk straight into the core of distributed systems: unique ID generation, read/write skew, caching, and capacity math you can do on a whiteboard.

The two operations — and why they’re wildly asymmetric

There are only two endpoints. What matters is that they are not balanced:

Write — POST /shorten
  • Long URL in → short code out
  • Happens once per link
  • Must produce a globally unique code
  • Low volume: thousands/sec at most
Read — GET /{code}
  • Short code in → 301/302 redirect out
  • Happens on every single click
  • Pure key lookup — no computation
  • High volume: 100× the writes or more

That ~100:1 read:write ratio is the single most important fact about the system. It tells you the read path must be cache-first and the code must be a primary key you can look up in one hop — never something you compute or scan for at read time.

Why not just hash the URL?

The tempting first answer — “hash the URL, take the first few characters” — has a fault line the interviewer is waiting for.

Hash collisions are not a maybe; they’re a certainty as the keyspace fills (the birthday bound guarantees it). So a hash-based scheme needs a read-modify-write “is this code taken? if so, re-hash” loop on the write path — a race condition and a latency tax on every insert.

1. request2. lookup3. on miss4. 301/302 → long URLBrowserGET tiny.co/aB3xK9Redirect serviceCachecode → URLDatabasecode (PK) → URL
The redirect path. The browser hits the short domain; the service looks the code up (cache first, database on miss) and returns a 301/302 pointing at the original URL. The browser then makes a second request to the real destination.

Six characters or seven?

The short code is a number written in base62. The length you pick is a capacity decision, and the arithmetic is clean enough to do live:

  • 6 chars: 62⁶ ≈ 56.8 billion codes.
  • 7 chars: 62⁷ ≈ 3.52 trillion codes.

At a sustained 1,000 new links per second, seven characters would take roughly 112 years to exhaust. That’s why bit.ly-class services settle on 7 — short enough to type, long enough to never run out.

The members-only build picks up exactly here: the three ways to generate that code (counter vs. hash vs. a Key Generation Service), an interactive forge where you watch each strategy encode a URL and handle collisions live, the cache-first read path and the 301-vs-302 tradeoff that quietly decides whether you get click analytics, custom aliases, and the full multi-language base62 codec.

Members only

Keep reading with Premium

You've reached the members-only part of this deep-dive — the full implementation, the interactive ring simulator, and the step-by-step walkthrough. Unlock it with a membership.

Related Articles