Scenario: URL shortener
Generate codes that are unique and unguessable off the hot path, then answer every click from a cache with a 302.
Predict first
Before you read: predict
ExamHall lets a candidate create share links for her exam result (exh.al/r/…), each revocable on its own. Each code is 8 base62 characters (0–9, A–Z, a–z). Over a season 200,000 share links are created, and 30,000 of them are a second link to a result that already has one. A link's code changed to the code one step up in base62 order must not open another live link.
Which generator gives every link a code of its own and meets that rule?
The 30-second version
A URL shortener maps short codes to long URLs, and clicks outnumber new links a thousandfold. Two deep dives decide it. Codes: a counter is unique but guessable; random codes need a unique check and a redraw; a truncated hash repeats for the same URL and collides. Redirects: 301 lets browsers skip you; 302 sends every click through you.
Generate codes that are unique and unguessable off the hot path, then answer every click from a cache with a 302.
How it works
Step 1 of 13
In the kitchen
- a tag number standing for a long register entry → a code standing for a long URL (step 1)
Analogy: A cattle farm's ear tags
Every calf wears a tag with a short number, and the national register maps it to the animal's long record.
| On the farm | In the shortener |
|---|---|
| a tag number standing for a long register entry | a code standing for a long URL (step 1) |
| the farm orders a numbered batch of tags in advance | a counter block per server (steps 3, 5) |
| a batch lost in a barn fire | a block lost in a crash (step 5) |
| the tag after your calf's is a neighbour's calf | a counter's next code is someone's link (step 4) |
| numbering each calf from its mother's tag: twins get one number | a hash of one URL gives one code (step 8) |
| the market inspector keeps the day's lot list instead of ringing the register | the cache in front of the database (step 11) |
Breaks down when: a tag is read by eye at the market, every time. Nothing on the farm remembers a redirect and skips the register, as a browser does after a 301 (step 9).
Contrasting case: a register that issues numbers at random and checks each against its book. Nobody can guess a neighbour's tag, and the price is one lookup per new tag (steps 6–7).
In real terms: pick the generator for uniqueness and guessability, and the redirect code for who must see each click.
Examples, run for real
4.1 ExamHall EXH-3880: result links that follow each other
ExamHall's result-share links took their codes from a counter, so the link issued after candidate 1043's was candidate 1044's. A test that decodes live codes and looks for neighbours catches it.
4.1 before: counter codes · candidate 1043's link 0000h, the next link issued 0000i (candidate 1044) · live codes whose next code is live 9,999 of 10,000 · check "no live code's next code is live": FAILS
4.1 MR !4180: 8 random characters, unique, redrawn on a clash · live codes whose next code is live 0 of 10,000 · redraws 0 · check: PASSES
MR !4180 draws 8 random characters, keeps them unique in the table and redraws on a clash, so no live code's neighbour is live (steps 4, 6–7).
4.2 A truncated hash clashes long before the codes run out
A streaming service hashes 20,000 different clip URLs and keeps the first characters.
4.2 20,000 different clip URLs, SHA-256 written in base62 · keep 4 characters (14,776,336 codes): 12 URLs get a code already taken · estimate n(n-1)/2 ÷ codes = 13.5 · keep 7 characters: 0
With 4 characters, clashes appear at 20,000 URLs out of 14.8 million codes, close to the n²/2|S| estimate (steps 6, 8).
4.3 The read path, and where a click is counted
4.3 1,000 redirects over 20 codes, cache in front of the database · database reads 20 · click written inside the redirect: 1,000 database writes on the redirect path · click appended to a log, flushed per 100: 0 on the redirect path, 10 batched writes
The cache takes the database out of the read path; writing each click inside the redirect puts it back. A log written in batches keeps the redirect to one cache read (steps 11, 13).
Try it
Answer first, then check. Nothing is saved.
Question 1 of 6
A streaming service will create 10 million share links a year for 10 years, and each link will be opened about 1,000 times. Each link's code is the next value of a counter, written in base62 (0–9, A–Z, a–z).
What is the fewest characters that still gives every link its own code?
Question 2 of 6
A video service's share links (clip.example/r/k7Qp2) answer 301 Moved Permanently with a Location to the clip page and no Cache-Control header. The team wants every open of a link to reach the shortener to be counted, and a revoked link to stop opening even for a viewer who opened it before. A viewer opens one link three times in the same browser; it is revoked just before her third open.
Which change meets both goals?
Question 3 of 6
A concert's presale link tix.example/r/Pz81 expires at 21:00. Redirects read the code's mapping from a cache that keeps an entry 60 minutes after loading it from the database; only a database read sees that a link has expired, and it is then refused (410). The entry was loaded at 20:40. Fans open the link at 20:50, 21:05, 21:20 and 21:35.
Which change refuses every open after 21:00 and still answers the 20:50 open from the cache?
Question 4 of 6
A podcast's short link answers every open from a cache. At 09:00 an episode goes out and the link is opened 3,000 times in the first minute, evenly spread; after that it is opened once every 2 minutes, from 09:02 to 09:30. The team wants every open in the database's click count within a minute of it, with at most 10 database writes in any one minute.
Which way of counting opens meets both?
Question 5 of 6
A payments app's receipt links take codes from a shared counter in blocks of 1,000: a server asks for the next block, then issues its values one by one from memory. Server 1 takes values 1–1,000 and server 2 takes 1,001–2,000. Server 1 issues 400 codes, then crashes and restarts, and issues 700 more. Server 2 issues all 1,000.
Afterwards, how many codes were issued twice, and how many values below the highest issued were never used?
Question 6 of 6
A chat app shortens links people paste. A link's code is the first 7 base62 characters of the SHA-256 of the long URL, and each (code, URL, owner) row is inserted under a unique constraint on the code. Owners see their own link's clicks and can delete their own link. At 10:00 Ana shortens a meeting URL. At 10:05 Ben pastes the same URL, and his insert is refused: the code is taken.
Which change gives Ben a code he owns and leaves Ana's row untouched?
Go deeper
Pro tips
- Say the read-to-write ratio out loud before drawing anything, with the two numbers it comes from.
When: the first minutes of a shortener round, before you pick a database or a code generator (step 1). Verify:
Status: RAN.tip 100M daily users x 5 redirects ÷ 86,400 s = 5,787 redirects a second · 100,000 new links a day = 1.2 a second · ratio about 5,000 to 1
Source
quote-check.mjs finds every passage below verbatim in its saved text. The row names exactly these two sources. Valid as of 2026-10-13.
- Hello Interview, Design a URL Shortener Like Bit.ly: https://www.hellointerview.com/learn/system-design/problem-breakdowns/bitly (
hellointerview-bitly.txt). The row's first source. Quoted: "we might see 1000 clicks (reads) for every 1 new short URL created (write)"; "Sequential counters also produce predictable short codes, making URL enumeration possible."; "the probability the next randomly generated code collides is n / |S|"; "implement a UNIQUE constraint on the short code column and retry with bounded attempts"; "the same long URL always maps to the same short code without needing to query the database"; "If Redis fails before replicating the latest counter, you might lose a few values, but since we only need uniqueness (not continuity), this is acceptable."; "Browsers typically cache this response, meaning subsequent requests for the same short URL might go directly to the long URL, bypassing our server."; "we should set the cache TTL to match or be shorter than URL expiration times so stale entries are automatically evicted." Supports steps 1, 3–8, 11–12 and the tip. - IETF, RFC 9110: HTTP Semantics, §15.4.2 and §15.4.3: https://www.rfc-editor.org/rfc/rfc9110.html (
rfc9110.txt). The row's second source. Quoted: "A 301 response is heuristically cacheable; i.e., unless otherwise indicated by the method definition or explicit cache controls" and, for 302, "Since the redirection might be altered on occasion, the client ought to continue to use the target URI for future requests."
Hello Interview's "100M DAU … 5 redirects per day" and "100k new urls are created per day" are the tip's inputs.
Related lessons
Checked against the tools and docs as of 2026-10-13.