Design TinyURL

A URL shortening service handling 100M URL creates per day and 1B redirects per day. Covers short code generation, caching strategy, redirect semantics, consistency tradeoffs, and abuse prevention.

In Progress URL Shortener Read-Heavy 10:1 Caching · Hashing ~45 min interview
01 Requirements 02 Estimation 03 API Design 04 Data Model 05 High-Level Design 06 Deep Dive Component Deep Dives
01 Requirements Clarification ⏱ ~5 min
RequirementDecision
Create short URLGiven a long URL, return a unique short alias — e.g. tinyurl.com/abc1234
Redirect short URLHTTP 301 or 302 redirect to the original long URL
Custom aliasIn scope — user can optionally specify their own short code
URL expiry / TTLIn scope — URLs can have an optional time-to-live
AnalyticsOut of scope — click counts, geo, referrers deferred
User accountsOut of scope — no auth required to create or use URLs
Scale100M URLs created/day · 10:1 read:write → 1B redirects/day
LatencyRedirect p99 < 50ms — speed is the product
Availability99.99% — a down TinyURL is very visible
ConsistencyEventual OK for reads; write uniqueness must be guaranteed
DurabilityShort codes must not be lost — permanent links expected
Key scope call

301 vs 302 is a product decision, not just a technical one. 301 (permanent) is cached by browsers — reduces server load but kills analytics. 302 (temporary) hits the server every time — enables tracking. Since analytics is out of scope here, 302 + aggressive server-side cache gives the best balance.

02 Capacity Estimation ⏱ ~5 min
Write RPS
~1,160
100M URLs ÷ 86,400s
Read RPS
~11,600
10:1 read:write ratio
Storage / year
~1.8 TB
500 bytes × 100M × 365
Storage / 5 yr
~9 TB
Manageable single cluster
Code space (7 chars)
3.5T
62⁷ with [a-zA-Z0-9]
Cache memory
~170 GB
20% daily reads × 500B
What the numbers tell us

Write load is moderate (~1K RPS) — manageable without exotic solutions. Read load is heavy (~12K RPS) — the design must be read-optimized with aggressive caching on the redirect path. The 3.5T code space gives us ~97 years of runway at current scale before exhaustion.

03 API Design ⏱ ~5 min

REST API. Three endpoints covering the full functional scope.

Method + PathRequestResponse
POST /urls Body: long_url, optional alias, optional ttl_days { short_url, expires_at } — 201
GET /{short_code} HTTP 302 → Location: long_url
DELETE /urls/{short_code} 204 No Content
Design decisions

No auth for MVP. Rate limiting at the load balancer (token bucket per IP) substitutes. Custom alias: if alias is taken, return 409 Conflict — don't silently override. DELETE: soft-delete in DB + cache invalidation, not hard purge, so we can detect reuse attempts.

04 Data Model ⏱ ~5 min

Single primary entity. Primary access pattern: given a short_code, return long_url. This is a pure key-value lookup — O(1), no joins, no range scans on the hot path.

FieldTypeNotes
short_codeVARCHAR(7)Primary key / partition key. Base62 [a-zA-Z0-9].
long_urlTEXT (≤2048 chars)Target URL. Validated on write.
created_atTIMESTAMPUTC. Immutable after creation.
expires_atTIMESTAMP NULLNull = no expiry. Used by cleanup worker + TTL index.
is_deletedBOOLEANSoft delete flag. Prevents code reuse on deleted URLs.
user_idVARCHAR NULLReserved for future auth. Null for now.
Storage choice

Cassandra or DynamoDB. Access is by short_code (point lookup), write throughput is ~1K RPS, schema is simple, and no joins are needed. NoSQL wide-column handles this cleanly with built-in TTL support and horizontal scaling. Could use Postgres at this scale — the write volume is comfortable — but NoSQL removes connection pool pressure at 12K read RPS and gives us clean sharding when we need it.

05 High-Level Design ⏱ ~10 min
🏗️

Architecture diagram — coming from our discussion session

This section will include the full write path + read path architecture diagram, component table with decisions, and the short code generation approach (hash vs. token service).

06 Deep Dive & Tradeoffs ⏱ ~15 min
🔬

Deep dives — built from our session

Will cover: short code uniqueness at scale, cache warming + thundering herd, 301 vs 302 tradeoff analysis, DB bottleneck at 10× scale, and abuse prevention strategy.

Component Deep Dives
⚙️

Component-level design — added after the session

Planned components: Short Code Generation Service (hash + retry vs. token pre-generation), Cache Layer design (write-through, eviction, warming), Cleanup Worker (TTL scanning + soft delete), and Rate Limiter (token bucket per IP at LB layer).