Design a URL shortener
How do you turn a long tracking link into seven characters, and serve it fast for years?
Why does one SMS cost three?
By spring the kitchen delivers 2,000 lunch boxes a day across Pune. Every order sends one text message when the box leaves: “Your dabba has left. Track it here,” with a link.
The month’s SMS bill does not match the month’s orders. About 60,000 messages went out. The bill is for about 140,000.
Pull up one message and the reason is in the link. It is 105 characters on its own: a long tracking address with an order id, a language and a source tag. An English message with that link runs past 160 characters, the limit of one SMS, so the phone network splits it into two billed parts. Customers who chose Marathi get their text in Devanagari script, which the network encodes differently. One Marathi SMS holds only 70 characters, so those messages go out in three parts. Most of what the kitchen pays for is the long address.
The usual answer is a short link: seven or eight characters after a short domain, and every message fits in one SMS. The quickest way to get one is a free public shortener, set up by lunch. But then every link the kitchen has ever sent depends on that company keeping its rules the same.
There is a second reason to own the shortener. Since October 2024, India’s telecom regulator requires businesses to register the links they send by SMS; messages carrying unregistered links are blocked. A link on a domain the kitchen controls can be registered once and trusted.
So the kitchen builds one. Before reading on, guess how many characters a code needs: there are 4,000 new links a day, and each one opens a page with a customer’s name and address on it. The service looks small, and it hides an ID problem, a privacy problem and a caching problem.
Pause and predict Codes from a counter are the shortest possible. For tracking links, what goes wrong?
What must never go wrong?
Start with who uses the system and what is outside it. This is the C4 System Context diagram: people, our one system, and the systems it talks to.
The first non-functional requirement is the one the accountant would write: a link, once sent, must always lead where it promised, and nowhere else.
Core entities, in two minutes
Before any API, name the nouns: a Link (code, long URL, expiry), the Owner who created it (the ordering platform, a cook), and Clicks (counted per link per day). The API step will be built around these resources.
The estimate that changes the design
Open the estimator with the first preset, then switch to “Public URL shortener”.
At the kitchen’s scale: 4,000 links a day is 0.05 writes a second. Five clicks each is 0.23 reads a second, about 2.3 at a tenfold lunch peak. Five years of links is 7.3 million rows of about 500 bytes: 3.65 GB. That is one small PostgreSQL database, with room to spare. The estimate removes work: no sharding, and the database’s own memory will hold the hot rows.
At the scale interview books use (100 million new links a day, ten reads per write) it is 1,157 writes and 11,574 reads a second on average, and 182.5 TB of unique data after ten years. That design needs sharding and a cache tier. The functional requirements are the same, and only the machines differ, so the logic is designed once and sized twice.
The obvious version, and how it breaks
The first idea is neat. Every order already has a numeric id. Write that number in base62 (digits, lower case, upper case) and it becomes a short code: order 916,132,832 becomes 100000. Add a route to the ordering app that turns the code back into a number and redirects.
It works, and the SMS bill falls by half.
Pause and predict Order 916,132,832 has the code 100000, and the next order gets 100001. A customer mistypes one character of her code. What does she most likely see?
Try it yourself: change a code and see whose page opens.
Sequential codes have three problems:
- They can be guessed. Counting upward walks through every customer’s tracking page.
- They leak business data. Two links a day apart tell a competitor how many orders the kitchen took that day.
- They tie links to orders. A cook’s menu link has no order id, so it cannot have a code at all.
The first problem is a privacy incident: strangers can read each other’s addresses. The fix is to separate the code from anything meaningful.
A mental model
Seen this way, the whole design is a key-value lookup with three questions around it. How are keys made (so they are short, unique and unguessable)? How are lookups kept fast when one link is opened by thousands? And what happens when a part fails?
- Redirect (301 versus 302)
- An HTTP response that says “not here, go there”, with the new address in a
Locationheader. The browser follows it automatically. - For example:
302 Found, Location: https://dabba.example/orders/track?order=…
Counter or random codes?
Two goals pull against each other here: the shortest possible code, and a code nobody can guess.
Both are correct designs for some system. A public shortener whose links point to public pages might take the counter. Ours point to private pages, and that decides it. (A third path exists: run the counter through a keyed, reversible scramble so codes look random but never collide. It works, at the price of more code and a key to protect.)
What to remember
- A short link is a pointer: the code is a key, the long URL its value, and a redirect is one key lookup.
- Codes must be short, unique and, when links open private pages, unguessable. Random 8-character base62 codes with an insert-if-absent check give all three.
- Use 302 for links that can expire or be disabled; a 301 may be cached by browsers indefinitely.
- Keep the redirect path read-only: look up through a cache, and count clicks asynchronously.
- Let the estimate decide the machines. The same design runs on two servers or on a sharded fleet.
A short code is a key into a table: make it short and unique, and, when it opens a private page, impossible to guess.
In the real world
Real shorteners add what our toy leaves out: malware and phishing checks before a link is created (a shortener is a favourite tool of spammers), abuse reporting, link previews, custom domains per customer, and analytics pipelines that can count billions of clicks. Many serve popular redirects straight from CDN edges.
The core stays what you built: a key, a value, a fast lookup, and codes nobody can guess.