DevOpsInterviews logo
← DevOps System Design & Architecture / 15
medium★ EssentialAmazon & AWSFlipkartMicrosoft

Design a URL shortener like bit.ly. What breaks first once the toy version works?

The most rehearsed design question, which is exactly why the interesting parts are the ones blog posts skip: redirect semantics, key generation under failure, and analytics kept off the hot path.

Grounded in researched DevOps, SRE and platform engineering interview loops, written to a senior-engineer editorial bar, and never padded to hit a word count.

TL;DR: Storage is the trivial part; read volume and analytics decide the design. Use a counter-driven base62 key, serve redirects like a CDN problem, emit click events asynchronously, and pick 302 with an explicit no-store cache policy when each redirect must reach your service, accepting a per-click hop as the price.

How to approach it

Pin three numbers before drawing anything: writes per year, read-to-write ratio, and whether clicks must be counted. Then say which constraint dominates, because the standard diagram is drawn for a read-heavy service and the answer changes if writes or analytics dominate instead.

A strong answer

Numbers first. Assume 500 million new links a year at roughly 500 bytes per row including metadata: about 250 GB annually, barely a terabyte after years and indexes. Storage never decides this design; reads do. Shorteners see 100:1 or higher read-to-write, so a service creating 500M links a year realistically serves billions of monthly redirects, at 100 redirects per new link that is 50 billion per year, about 1,585 RPS average. A 10k RPS design point is about 6.3 times that mean; choose further campaign headroom explicitly. Design the redirect path like static asset delivery, because it is one.

Key generation. A monotonic counter encoded base62 needs seven characters for 62^7, about 3.5 trillion keys. Counters beat hashing the URL because there is no collision path to handle; the cost is distributing the counter, solved by handing each app node pre-allocated ranges of, say, 100,000 keys rather than calling a central sequencer per write. Sequential codes are guessable, which is fine for public marketing links; private links get a random token plus permission checks at redirect time.

Redirect semantics, where the marks are.

301 permanent302 temporary
Browser cachingHeuristically cacheable unless controlledCan cache with explicit freshness
Click analyticsCached redirects bypass origin eventsUse Cache-Control:no-store for origin observation
Backend loadFalls over timeConstant
Right choiceLinks that never change or expireAnything you might retarget, measure, or kill

Use302 with explicit Cache-Control when retargeting or observation requires it because retargeting and measurement are the product. State the reversal unprompted: purely static links with no analytics mandate can go 301 and hide behind edge caching.

Serving path. Stateless app tier behind a load balancer, Redis cluster holding short-code lookups, misses falling through to a read replica hitting a unique index. At 10k redirects per second with a 95 percent cache hit rate, misses are 500 point lookups per second, comfortable for Postgres or MySQL. At bit.ly scale the mapping lives in an edge key-value store so redirects resolve near the user.

Analytics off the hot path. Redirect handlers append a click event (code, timestamp, coarse geo, referrer) to Kafka and return immediately; rollups land in a columnar store seconds later. Nobody who has operated one of these performs the analytics write inside the redirect request.

Also name the boring essentials: malware and phishing scanning before a link activates (shorteners are abuse infrastructure), per-client rate limits on creation, custom domains, and deletion that propagates a tombstone to the edge within cache TTLs.

What interviewers probe next

"Links must expire after 24 hours. What changes?" 301 dies instantly: a cached permanent redirect keeps working past expiry and cannot be recalled. Use explicit cache directives and expiry checks, ensuring any edge/browser freshness does not outlive the link.302alone does not prevent caching; no-store is appropriate when every click must be observed. The memorised diagram omits this mutation entirely.

"Where do keys come from if a datacenter is isolated?" Range allocation with generous block sizes rides through hours of isolation; two islands never issue overlapping ranges.

"A custom alias collides with a counter code." Same table, same unique index; alias creation reserves its code transactionally and conflicts return a clear error rather than silent suffix mangling.

Common mistakes

Drawing the six-box architecture (client, LB, app, cache, DB, analytics) with no numbers attached, which reads as rehearsed rather than reasoned.

Choosing 301 everywhere and then promising real-time click dashboards, a contradiction in one breath.

Skipping abuse handling entirely; a shortener that happily wraps phishing links gets domain-blocklisted by browsers and email providers, which kills the product.

References

HTTP caching RFC9111.

That one was free, and so are 18 answers per topic without an account. Signing in doubles that to 28, keeps your bookmarks, and tracks which topics you keep getting wrong.one Google click · no card · nothing to cancel
HOW DID IT GO?
0
UP NEXT ON YOUR JOURNEY
NOTES & DISCUSSION · 0

Nothing here yet. Say how you would answer it.