A URL shortener that is mostly a read problem
The interview classic, and the reason it is asked: almost everyone designs the write path, and almost all of the traffic is on the read path.
The brief
Take a long URL, return a short one. Visiting the short one redirects to the long one.
Links never expire unless the creator deletes them. Anyone can create one without an account.
Requirements
Functional
- Create a short link for a URL
- Redirect a short link to its target
- Let the creator delete a link they made
Non-functional
- A redirect is on the critical path of somebody else's page load — treat its latency as a budget, not a target
- Losing a link is worse than briefly failing to create one
- Short codes must not be guessable in bulk if anyone will use this for anything private
Back-of-envelope
Assume
- 1 million new links a day — this is the number to argue with first
- 100 reads per write, which is the ratio that decides the whole design
- 500 bytes stored per link: the target URL, the code, an owner, a timestamp
Therefore
- Writes: 1e6 / 86,400 ≈ 12 per second. This is not a scaling problem. A single database handles it.
- Reads: 12 × 100 ≈ 1,200 per second, and this is where the design goes.
- Storage: 1e6 × 500 B ≈ 500 MB a day, ≈ 180 GB a year. Fits on one machine for years; plan sharding for when it does not, not now.
- A short code from 62 characters: 62^7 ≈ 3.5e12. At a million a day that is over 9,000 years of codes.
Notice what the arithmetic did: it removed the write path from the discussion entirely. If your reads-per-write assumption were 2 instead of 100, this would be a different design — which is why the assumption is written down rather than folded into a total.
The interface
What is stored
code (primary key, 7 chars) · target · ownerId (nullable) · createdAtThe entire read pattern is one point lookup by primary key, so the table wants no other index. Every index you add is a write cost paid to speed up a path that is one percent of the traffic.
code (primary key) · deletedAtA tombstone rather than a removed row, so a code is never re-issued. Re-issuing means an old link quietly starts pointing at a stranger's URL, which is the worst failure this system has and leaves no trace in any log.
The design
The decisions
Each of these could go the other way. The choice, the reason, and what it costs — a design that lists only what it chose teaches the choice; one that lists what it gave up teaches the judgement.
What breaks first
In order. Each names what you would actually observe, and each fix carries its cost.
When something fails
Scaling it
Each step is triggered by a number, not a feeling — and carries what it costs.
What gets probed
The design is the easy half. These are where the conversation goes, and each has a defensible answer above.
- What happens when two requests generate the same random code at the same moment?
- A link is deleted. How long can it keep redirecting, and who decided that?
- One link goes viral and is 90% of your traffic. What breaks first?
- How would you add per-link click counts without putting a write on the redirect path?