Skip to main content
Let’s take a look at our first system-design interview problem. Design a URL shortener (like Bitly). A user pastes a long URL and the service returns a short, neat URL that redirects to the original link. This is a common, real-world product: it makes long, unwieldy links easy to share. Example flow:
Anyone who clicks the short URL is redirected to the original long URL. The problem looks simple on the surface; interviewers use this prompt because the interesting part is the design decisions and trade-offs. We will apply a six-step system-design framework to this problem. Below we cover the first three steps: clarify requirements, estimate scale, and define the API / data model.

Step 1 — Clarify requirements

Only ask clarifying questions that would change the design. Useful questions include:
  1. Can users pick custom short links (e.g., shortlink.io/kodekloud) or must the system generate an opaque code?
    • If custom links are allowed, you need to check for collisions, reserve names, and possibly rate limit creations for a chosen string.
  2. Do short links expire, or are they permanent?
    • If they expire, you need a cleanup pipeline and extra checks at redirect time.
  3. Do you need analytics (click counts, geolocation, timestamps)?
    • Analytics introduces additional writes on redirects and often requires asynchronous logging to avoid slowing redirects.
Assumptions for this lesson:
  • Custom links are NOT allowed (system-generated only).
  • Links do NOT expire (they live indefinitely).
  • Analytics are optional / nice-to-have (we’ll design core system first).
If custom links were supported, the UI/UX and backend must handle name reservation and conflict resolution. Example custom-link flow (kept for context):
Restate scope to the interviewer: create short links that redirect to original URLs, no custom links, links are permanent, and analytics are optional.

Step 2 — Back-of-the-envelope estimation

Estimate only the numbers that affect design choices. Question 1 — how many new links per day?
Assume 1,000,000 new links per day.
A dark-themed app screen with a highlighted "Estimate" step showing the large text "1,000,000" and the caption "new links a day." A small chat bubble at the bottom left says "Let's say a million a day."
One million new links per day is roughly 12 new links per second — easily handled by modern databases for writes. Question 2 — how many clicks per short link?
Assume each created link gets ~1,000 clicks over its lifetime. This implies a read-to-write ratio of roughly 1000:1, i.e., the system is heavily read-biased.
A dark-themed diagram showing a single pink user writing to a pair of servers that fan out to many teal reader icons labeled "1000 reads." The graphic is captioned "Read heavy, 1000 to 1" with side notes about writes per second.
Because reads dominate writes by several orders of magnitude, prioritize optimizing the redirect path: reduce latency, add caching (CDN or in-memory), and design for horizontal read scaling.
Question 3 — how many links will exist in total?
At 1,000,000 new links/day for 10 years, you approach ~3.65 billion records. That influences storage choice, indexing, and sharding strategy.
Quick summary of design-relevant numbers:

Step 3 — Define the API and data model

At minimum the service needs two endpoints:
  • Create a short link (POST): client sends a long URL, server returns a short code or full shortened URL.
  • Redirect (GET): browser requests the short URL, service responds with an HTTP 301/302 redirect to the long URL.
A simple key-value mapping (short_code -> long_url) is sufficient: the short code is a small key used to fetch a single value. Example minimal API:
API endpoints table:
A stylized diagram of a "one to one" URLs table showing columns short_code and long_url with example shortcodes mapped to full URLs and arrows labeled "KEY" and "VALUE." Two small icons labeled "INTERVIEWER" and "YOU" sit in the bottom corners.
Storage choice recommendations
  • Access pattern: single-key lookup on short_code -> long_url. No complex joins or transactions needed.
  • Start simple: a relational database (Postgres) with an indexed short_code column is reasonable for moderate scale: durability, secondary indexes, and easy operations.
  • For large scale (billions of rows, huge read traffic): consider sharding by code prefix or migrating reads to a distributed key-value store (e.g., DynamoDB, Cassandra) and adding caching layers.
Design considerations and next steps
  • Short-code generation
    • Fixed-length Base62 (alphanumeric) codes give compact URLs.
    • Options:
      • Random codes (check for collisions; regenerate if collision).
      • Sequential IDs encoded in base62 (no collisions but predictable).
      • Hashing the long URL (handle collisions and length).
    • Ensure collision handling and consider partitioning strategy for generation if distributed.
  • Redirect performance
    • Cache hot mappings in-memory (Redis or in-process LRU) and/or use a CDN/edge-cache for redirects.
    • Serve redirects from edge locations when possible to minimize latency.
  • Analytics
    • Don’t write synchronous counters on redirect (this can throttle redirects). Instead:
      • Emit lightweight events to a queue (e.g., Kafka) and process asynchronously.
      • Aggregate click counts into a separate analytics store.
  • Consistency and durability
    • Writes (create short link) should be durable; on create return only after persistence to avoid losing mappings.
    • Redirect reads can be eventually consistent if you accept a brief window where a newly created link might not immediately redirect (but typically prefer immediate availability).
  • Scaling and availability
    • Read-heavy workloads: scale read replicas or use a cache tier.
    • Partition data (shards) once single DB throughput becomes a bottleneck.
    • Use monitoring and autoscaling for the redirect service to handle flash crowds.
Further reading and references This completes the initial requirements, estimations, and API/data-model design for a basic URL shortener. Next steps in a full interview would include sketching the system architecture diagram (load balancer, app servers, cache, DB, queue for analytics), defining failure modes and mitigation, and detailing operational concerns (backups, migrations, monitoring).

Watch Video