Katkat

System Design: A Short-Link Service That Redirects in Milliseconds

VercelSoftware Engineer · Onsite

Last updated

Design a service that turns long URLs into short, shareable links and redirects visitors to the original destination with minimal latency. Tests capacity estimation, collision-free code generation under concurrent writes, a read-optimized data model, and how to scale and harden the redirect path.

Design a link-shortening product: a user pastes in a long URL and gets back a short one; anyone who opens the short link lands on the original destination almost instantly.

Two very different workloads sit behind this one product: creating a link, which is relatively rare and can tolerate a little latency, and following a link, which happens constantly and has to be fast no matter what. Your design should treat them separately rather than forcing both through the same code path and data store.

What to cover

  • Scale. Make your own assumptions about how many links get created per day, how many redirects happen per day, and how long links need to be retained, then size storage and throughput from those assumptions.
  • Short code generation. How do you produce a code that two people creating a link at the same instant can never collide on? How long does the code need to be, and why?
  • Storage and lookup. What does a link record look like, and what storage engine fits a workload that's almost entirely point lookups by short code?
  • The redirect path. What sits in front of your database so a redirect doesn't need to touch it on every request? What HTTP status code do you send back, and what does that choice commit you to?
  • Scaling and resilience. How does the system grow past a single region, and what happens to redirects if a dependency is unavailable?
  • Abuse and analytics. How do you keep someone from shortening links to malicious destinations, and where do click counts get recorded without slowing down the redirect itself?

Clarifying questions worth raising

  • Do short links expire, and can a user delete or retarget one after creation?
  • Can a user request a specific custom slug instead of a generated one, and how does that interact with the generated-code space?
  • If the same long URL is submitted by two different users, should they get the same short code or independent ones?
  • How exact do click counts need to be — is an approximate, slightly-delayed count acceptable?
  • Should the mapping be guessable (sequential) or does it need to resist enumeration?

Example of the shape of an answer, not the full solution

Suppose you assume 2 million new links per day and a 100:1 ratio of redirects to creations — roughly 200 million redirects per day, or on the order of 2,300 redirects per second on average (several times that at peak). That single estimate should already be steering your choices: optimize the read path aggressively, and don't be afraid to make link creation do a little more work (like a uniqueness check) since it's three orders of magnitude rarer.

Hints

Hint 1

Size the system before designing it — redirects-per-second and total stored links change which storage engine and caching strategy actually make sense.

Hint 2

A random code generated independently per request risks collisions at scale; either generate from a counter (and encode it) or check-and-retry against a uniqueness constraint, and know the trade-offs of each.

Hint 3

The redirect path should be answerable from a cache or a CDN edge in the common case — treat a database hit on every redirect as something to design away, not something to optimize later.

Hint 4

Decide early whether redirects are 301 or 302 and say out loud what each choice costs you (browser caching makes a 301 'sticky' and can make click analytics and future retargeting harder).

Follow-up questions

  • One short link suddenly accounts for 40% of total redirect traffic for a day. Walk through what happens to your cache, your database, and your analytics pipeline, and what you'd change afterward.
  • How would you let users reserve a specific custom slug while a background job is still generating random codes from the same namespace, without a race condition letting both land on the same string?
  • If you later need to support link expiration, what has to change in the cache so an expired link stops redirecting promptly instead of serving a stale cached destination?
  • How would you get an accurate unique-visitor count per link without adding a synchronous dependency to the redirect request?