System Design Problems interview question · Most asked

Design a URL shortener (like bit.ly).

Summary

Generate short unique codes mapped to long URLs, serve redirects with very low latency from a cache, and record click analytics asynchronously. Reads dominate writes (~100:1), so the redirect path is cache-first.

Requirements

  • Create a short link for a long URL (optional custom alias, expiry)
  • Redirect short → long with low latency (p99 < 50 ms)
  • Click analytics per link
  • Non-functional: highly available reads, links never collide, 100M new links/month

Back-of-the-envelope

  • 100M links/month ≈ 40 writes/s; 100:1 reads ≈ 4,000 redirects/s (peaks 10×)
  • ~500 bytes/link → ~600 GB over 10 years
  • 7-character base62 codes give 62^7 ≈ 3.5 trillion combinations

API

POST /api/links        {"url": "https://...", "alias": "optional", "expires_at": "optional"}
→ 201 {"code": "aZ3kP9q", "short_url": "https://sho.rt/aZ3kP9q"}
GET  /{code}           → 301/302 Location: https://...
GET  /api/links/{code}/stats → {"clicks": 1234, "by_day": [...]}

Data Model

links(code PK varchar(10), long_url text, owner_id bigint, created_at, expires_at)
clicks(code, ts, country, referrer, ua_family)   -- append-only, in an analytics store

Architecture

Clients hit a CDN/edge, then stateless API servers. Redirects read from Redis (code → URL) with a database fallback (a key-value store or Postgres keyed by code). Link creation obtains a unique ID and encodes it in base62. Click events are pushed to a queue (Kafka) and aggregated by stream processors into an analytics store (ClickHouse).

Deep Dives

  • Code generation: a counter-based ID (range allocation per server from a sequence/ZooKeeper/DB) encoded in base62 avoids collisions; random codes need a uniqueness check; hashing the URL needs collision handling
  • 301 vs 302: 301 is cached by browsers (less load, fewer analytics); 302 keeps every click visible
  • Custom aliases: reserved words, uniqueness via unique constraint
  • Abuse: malware URL scanning, rate limits per user/IP

Scaling

  • Cache hot codes in Redis and at the edge; hit ratios above 90% are typical
  • Shard the links store by code
  • Analytics writes go through a queue, never in the redirect path
  • Multi-region read replicas for global latency

Comparison / Tradeoffs

Decision Option chosen Alternative Why
Code generation Counter + base62 Random or hash No collisions, short codes; counters are predictable (add salt/shuffle if needed)
Redirect status 302 301 Accurate analytics over fewer requests
Storage Key-value / Postgres by PK Graph or document DB Simple primary-key access pattern

Explanation

What interviewers look for

A structured approach: clarify requirements and scale, sketch the API and data model, draw the high-level architecture, then go deep on the hardest component and discuss trade-offs, bottlenecks and failure modes.

Follow-up questions

  • How would you prevent enumeration of codes?
  • How do you expire links and reclaim codes?
  • How do you count unique visitors?

More most-asked System Design Problems questions

← All System Design Problems questions