01

Requirements & scope

Problem Statement & Requirements

Functional Requirements

  • Given a long URL, generate a short, unique alias (e.g., https://short.ly/abc123)
  • When a user hits the short URL, redirect them to the original long URL (HTTP 301/302)
  • Users can optionally pick a custom short alias
  • Links can have an expiration time (TTL)
  • Analytics: track click count, referrer, geo, device (optional but expected in interviews)

Non-Functional Requirements

  • High availability — redirections must never go down
  • Low latency — redirect in < 10 ms (p99)
  • URL should not be guessable — no sequential IDs
  • Consistency — same long URL can map to multiple short URLs (user-specific), but a short URL must always resolve to exactly one long URL
  • Durability — once created, a short link must survive infrastructure failures

Out of Scope

  • User authentication/accounts (simplify for interview)
  • Link editing after creation
  • Bulk URL shortening API
02

Scale estimations

Scale Estimations

Traffic

MetricValue
New URLs created / day100M (write-heavy assumption)
Reads (redirections) / day10B (read:write = 100:1)
Reads / second~116K RPS
Writes / second~1,160 RPS
Peak reads / second~350K RPS (3x average)

Storage

MetricValue
Average URL length500 bytes
Metadata per URL100 bytes (created_at, expires_at, user_id, click_count)
Short key7 bytes
Total per record~607 bytes → round to 1 KB
Records over 5 years100M/day × 365 × 5 = 182.5B records
Storage over 5 years182.5B × 1 KB = ~182.5 TB

Bandwidth

MetricValue
Incoming (writes)1,160 × 1 KB = ~1.16 MB/s
Outgoing (reads)116K × 1 KB = ~116 MB/s

Cache

  • 80/20 rule: 20% of URLs generate 80% of traffic
  • Cache 20% of daily read requests: 10B × 0.2 × 1 KB = ~2 TB cache
  • Fits in a Redis cluster
03

Layered architecture

Phase 1 of 4 · Client & edge

Start with the entry points

First, define who uses the system and where requests enter. This is the boundary of the design, not yet a complete request path.

Client
Start with the two user actions: create a short link and follow an existing one.
API gateway
Separate creation from redirection, then protect both endpoints from abusive traffic.
Architecture after phase 1. Includes Client, API gateway. Client connects to API gateway.
Phase 1 — Start with Client, API gateway.SVGSVGEditable diagramEditable diagram

This first layer defines the system boundary. The next chapters add application logic and data dependencies. After examining the request paths and tradeoffs, we will add operational safeguards and bring the complete architecture together.

04

API & contracts

Phase 2 of 4 · Application & compute

Add the application logic

Keep the entry points and add the services that do the work. Give each service a clear responsibility before defining its contracts. Storage and background dependencies come next.

URL service
Validate URLs, enforce expiry, and resolve aliases. Stateless servers can scale horizontally.
Key generator
Generate non-sequential keys and use a conditional insert to detect collisions, retrying when necessary.
Architecture after phase 2. Includes Client, API gateway, URL service, Key generator. Client connects to API gateway. API gateway connects to URL service. URL service connects to Key generator.
Phase 2 — Added URL service, Key generator. Earlier layers remain in place.SVGSVGEditable diagramEditable diagram

API Design

Create Short URL

EXAMPLE
POST /api/v1/urls
Content-Type: application/json

Request:
{
  "long_url": "https://www.example.com/very/long/path?q=something",
  "custom_alias": "my-brand",     // optional
  "expires_at": "2026-12-31T00:00:00Z"  // optional
}

Response (201 Created):
{
  "short_url": "https://short.ly/abc123",
  "short_key": "abc123",
  "long_url": "https://www.example.com/very/long/path?q=something",
  "expires_at": "2026-12-31T00:00:00Z",
  "created_at": "2026-04-03T10:00:00Z"
}

Redirect (Read)

EXAMPLE
GET /:short_key
→ HTTP 301 (permanent) or 302 (temporary) redirect to long_url

301 vs 302 Tradeoff:
  - 301: Browser caches the redirect → less load on our servers,
         but we lose analytics visibility (browser skips us on repeat visits)
  - 302: Browser always hits us → more load but full analytics tracking
  → Use 302 if analytics matter; 301 if pure performance is the goal

Delete URL

EXAMPLE
DELETE /api/v1/urls/:short_key
→ 204 No Content
05

Data model

Phase 3 of 4 · Data & async work

Connect data and background work

The services now need their dependencies: durable state, fast lookups, or work that continues outside a request. Separate these responsibilities rather than treating every component as a database.

URL database
Persist each alias-to-URL mapping durably. Point lookups make a key-value access pattern a natural fit.
Redis cache
Cache popular redirects to avoid a database lookup on every request. Never serve links beyond their expiry.
Click stream
Publish click events outside the latency-critical redirect path, with bounded buffering on failure.
Architecture after phase 3. Includes Client, API gateway, URL service, Key generator, URL database, Redis cache, Click stream. Client connects to API gateway. API gateway connects to URL service. URL service connects to Key generator. URL service connects to URL database. Key generator connects to URL database. URL service connects to Redis cache. URL service connects to Click stream.
Phase 3 — Added URL database, Redis cache, Click stream. Earlier layers remain in place.SVGSVGEditable diagramEditable diagram

Data Model

URL Table (Primary)

URL Table (Primary)
URL Table (Primary)SVGSVGEditable diagramEditable diagram

Database Choice

OptionProsCons
DynamoDBManaged, auto-scaling, single-digit ms latency, partition by short_keyNo joins (not needed here), cost at extreme scale
CassandraLinear scalability, tunable consistency, great for write-heavyOperational complexity, eventual consistency
MySQL + shardingACID, familiar, strong consistencyManual sharding, operational burden at scale

Recommendation: DynamoDB or Cassandra — this is a key-value lookup workload with high write throughput. No joins, no complex queries.

06

Core design decisions

Key Generation — The Core Design Decision

This is the most important part of the design. How do we generate a short, unique, non-guessable key?

Option 1: Hash the Long URL (MD5/SHA-256 + Base62 Truncation)

Option 1: Hash the Long URL (MD5/SHA-256 + Base62 Truncation)
Option 1: Hash the Long URL (MD5/SHA-256 + Base62 Truncation)SVGSVGEditable diagramEditable diagram

Key space: Base62 with 7 characters = 62^7 = 3.5 trillion unique keys

Collision handling:

Option 1: Hash the Long URL (MD5/SHA-256 + Base62 Truncation)
Option 1: Hash the Long URL (MD5/SHA-256 + Base62 Truncation)SVGSVGEditable diagramEditable diagram
ProsCons
Deterministic — same URL → same hashCollisions require DB lookup + retry
Simple to implementSame long URL → same short URL (no per-user links)
No coordination neededMD5 is not cryptographically secure (fine for this use)

Option 2: Pre-Generated Key Pool (Key Generation Service — KGS)

Option 2: Pre-Generated Key Pool (Key Generation Service — KGS)
Option 2: Pre-Generated Key Pool (Key Generation Service — KGS)SVGSVGEditable diagramEditable diagram

How it works:

  1. Offline job generates random 7-char Base62 keys, stores in unused_keys table
  2. App server requests a batch (e.g., 1,000 keys) at startup, caches them in memory
  3. On URL creation, pop a key from the in-memory batch
  4. When batch runs low (< 200), fetch another batch asynchronously
  5. Mark keys as "used" in the DB atomically

Concurrency safety:

  • Use a two-table approach: unused_keys and used_keys
  • Move key from unused → used in a single transaction
  • If an app server crashes, its unused in-memory keys are "lost" — acceptable given the 3.5T key space
ProsCons
Zero collision — guaranteed uniqueNeed a separate KGS service
O(1) key generation — no DB check neededPre-generated keys take storage
Fast — just pop from in-memory cacheWasted keys if server crashes (negligible)
No hash computationSingle point of failure → need standby KGS

Option 3: Counter-Based with Encoding (Snowflake-style)

Option 3: Counter-Based with Encoding (Snowflake-style)
Option 3: Counter-Based with Encoding (Snowflake-style)SVGSVGEditable diagramEditable diagram
ProsCons
Zero collision — ranges don't overlapSequential/predictable (guessable)
No DB lookup for uniqueness checkRequires Zookeeper or similar coordination
Simple, efficientRange exhaustion needs re-allocation

Recommendation

Use Option 2 (KGS) for production systems:

  • No collisions, no coordination overhead per request
  • O(1) amortized key generation
  • Easy to make non-guessable (random keys, not sequential)
  • Can be made highly available with standby KGS replicas
07

Request flows

Detailed Flow Diagrams

Write Flow (URL Creation)

Write Flow (URL Creation)
Write Flow (URL Creation)Wide diagram — scroll horizontally.SVGSVGEditable diagramEditable diagram

Read Flow (Redirection)

Read Flow (Redirection)
Read Flow (Redirection)Wide diagram — scroll horizontally.SVGSVGEditable diagramEditable diagram

Analytics Flow (Async)

Analytics Flow (Async)
Analytics Flow (Async)Wide diagram — scroll horizontally.SVGSVGEditable diagramEditable diagram
08

Performance & caching

Caching Strategy

Cache Architecture

Cache Architecture
Cache ArchitectureSVGSVGEditable diagramEditable diagram

Caching Patterns

PatternHow It WorksWhen to Use
Cache-AsideApp checks cache → miss → query DB → populate cache✅ Best for this use case
Write-ThroughWrite to cache + DB on creationWastes cache on URLs that may never be read
Write-BehindWrite to cache, async flush to DBRisky — URL could be lost if cache crashes

Recommendation: Cache-Aside with Write-on-Create for popular URLs

  • On URL creation: don't populate cache (most URLs are rarely accessed)
  • On first read: query DB, populate cache
  • Exception: if we detect a URL going viral (high click rate), proactively cache it

Cache Warming

  • Preload the top 1% most-accessed URLs into cache on service startup
  • Use a daily batch job scanning analytics to identify hot URLs
09

Advanced design

Database Sharding & Partitioning

Sharding Strategy

Sharding Strategy
Sharding StrategySVGSVGEditable diagramEditable diagram

Recommendation: Consistent Hashing on short_key

  • Even distribution
  • Adding/removing DB nodes only requires moving ~1/N of the keys
  • Use virtual nodes (vnodes) for better balance — 150-200 vnodes per physical node

Replication

Replication
ReplicationSVGSVGEditable diagramEditable diagram
10

Edge cases

Handling Edge Cases

Duplicate Long URLs

  • Same user, same URL: Return existing short URL (dedup query on long_url + user_id index)
  • Different users, same URL: Generate separate short URLs (user isolation)

Expired URLs

  • Lazy deletion: On read, check expires_at → if expired, return 410 Gone
  • Background cleanup: Cron job deletes expired records, recycles keys back to KGS

Custom Aliases

  • Validate: 3-16 chars, alphanumeric + hyphens only
  • Check uniqueness in DB
  • Reserve a set of blacklisted words (profanity, reserved paths like /api, /admin)

Hot URLs (Viral Links)

  • A single URL getting millions of hits/second
  • Solution: Cache replication — replicate hot keys across multiple cache shards
  • Application-level: detect hot keys (e.g., > 1000 RPS) and fan out reads across replicas
11

Tradeoffs

Tradeoffs & Design Decisions Summary

DecisionOption AOption BChosenWhy
Key GenerationHash + collision checkPre-generated KGSKGSZero collisions, O(1), non-guessable
Redirect Code301 (permanent)302 (temporary)302Preserves analytics; 301 loses repeat visit tracking
DatabaseSQL (MySQL/Postgres)NoSQL (DynamoDB/Cassandra)NoSQLKey-value access pattern, high write throughput, linear scaling
CachingWrite-throughCache-asideCache-asideMost URLs are rarely accessed; avoid wasting cache on cold URLs
ShardingRange-basedConsistent hashingConsistent hashingEven distribution, graceful scaling
ID Length6 chars (56B keys)7 chars (3.5T keys)7 charsRoom for 5+ years at 100M URLs/day
AnalyticsSynchronous in request pathAsync via KafkaAsync KafkaDon't add latency to the redirect hot path
12

Reliability & fault tolerance

Phase 4 of 4 · Operations & resilience

Add operational safeguards

With the request paths and tradeoffs established, add the controls that help detect trouble and keep the system operating. The final diagram retains every layer introduced so far.

Observability
Track redirect latency, cache misses, collisions, and queue lag. Analytics failure must not stop redirection.
Architecture after phase 4. Includes Client, API gateway, URL service, Key generator, URL database, Redis cache, Click stream, Observability. Client connects to API gateway. API gateway connects to URL service. URL service connects to Key generator. URL service connects to URL database. Key generator connects to URL database. URL service connects to Redis cache. URL service connects to Click stream. Click stream connects to Observability.
Phase 4 — Added Observability. Earlier layers remain in place.SVGSVGEditable diagramEditable diagram

Reliability & Fault Tolerance

Single Points of Failure & Mitigations

Single Points of Failure & Mitigations
Single Points of Failure & MitigationsSVGSVGEditable diagramEditable diagram

Graceful Degradation

  • If cache is down → serve directly from DB (higher latency, still functional)
  • If KGS is down → app servers use remaining in-memory keys; alert for manual intervention
  • If analytics pipeline is down → buffer events locally, replay later
13

Production architecture

High-Level Architecture

High-Level Architecture
High-Level ArchitectureSVGSVGEditable diagramEditable diagram

Component Breakdown

Component Breakdown
Component BreakdownSVGSVGEditable diagramEditable diagram

Full System Architecture (Production-Grade)

Full System Architecture (Production-Grade)
Full System Architecture (Production-Grade)SVGSVGEditable diagramEditable diagram
14

Further exploration

What changes if one short link appears on a live television broadcast? Follow that single hot key through the cache, database, and analytics pipeline. Then consider a link whose owner changes its destination: decide how quickly existing cache entries must stop returning the old address.

15

Interview playbook

Interview Tips

  1. Start with requirements clarification — Don't jump into design. Ask about scale, custom aliases, analytics, expiration.

  2. Lead with the key generation discussion — This is the core algorithmic challenge. Discuss all three approaches, tradeoffs, and recommend KGS.

  3. Separate read and write paths — They have very different scale (100:1 ratio). This shows you think about system characteristics.

  4. Don't forget caching — With 100:1 read:write ratio, caching is critical. Discuss eviction, warming, and hot key handling.

  5. Mention 301 vs 302 — This is a subtle but important tradeoff that shows depth.

  6. Discuss cleanup of expired URLs — Shows you think about long-term system health and operational concerns.

  7. End with reliability — Walk through failure scenarios. "What happens if X goes down?" for each component.