CMD Guide
HomeSystem DesignSystem Design Problems

Designing a URL Shortening Service like TinyURL

1. Requirements and Goals

Functional:

Non-functional:

2. Capacity Estimation

Assume 500M new URLs/month and a 100:1 read:write ratio.

MetricValue
New short URLs~200/s
Redirects~20K/s
Storage (5 years, ~500 bytes/record)~15 TB
Hot cache (20% of daily traffic)~170 GB

3. API Design

4. Data Model

One table/collection urls:

FieldTypeNotes
short_keystring (PK)7-character base62 hash, ~3.5 trillion unique keys
original_urlstringIndexed for analytics/admin
created_attimestamp
expires_attimestampTTL cleanup
user_idstringOptional owner
clickscounterAggregated asynchronously

Which store? Billions of tiny rows, pure key–value access by short_key, no joins, no cross-row transactions — a key-value / wide-column store (DynamoDB, Cassandra) fits naturally and shards by key without ceremony. Partitioned Postgres/MySQL is perfectly fine at lower volume (tens of millions of links, one team, one region); the access pattern is what decides, not fashion — nothing here uses the relational features you would be paying for.

5. High-level Design

6. Detailed Design: Key Generation

Two common strategies:

For 7-character base62 keys, the space is 62^7 ≈ 3.5 trillion, enough for the estimated 30 billion records with room to spare.

KGS concurrency, range caching, and crash recovery

If every shorten call hits the database for the next free key, the KGS becomes the write bottleneck. The production pattern:

  1. Range lease. A KGS instance atomically claims a block of unused keys from a coordination store (e.g. ZooKeeper, etcd, or a single-row CAS on a key_counter table): KGS-1 gets [1_000_000, 1_010_000), KGS-2 gets [1_010_000, 1_020_000). No two instances receive overlapping ranges.
  2. In-memory cache. The KGS (or each app server that received a sub-range) holds the remaining keys in RAM and hands them out with no DB round-trip per write. When the local buffer is low, it claims the next range.
  3. Crash recovery. If KGS-1 dies with keys still in its RAM cache, that residual range is discarded, never reused. The huge key space (627 ≈ 3.5 trillion; even 6 characters gives ~57 billion) makes a few thousand lost keys acceptable; reusing a range risks two URLs mapping to the same short code.

Unguessability. A naive counter (or sequential range) hands out enumerable keys — an attacker who sees abc123x can walk the neighbouring codes and harvest other people's links, violating the not-guessable NFR. Close the gap at issue time: pre-generate the key pool and hand keys out in random order, or run the counter through a keyed bijection (e.g. a Feistel permutation over the 627 space) so consecutive counter values map to scattered, unpredictable codes. Range leasing still works unchanged — the ranges are over counter values, not over the issued codes.

ZooKeeper (or equivalent) is only for range coordination — the critical path of redirect still goes cache → DB, not through ZK.

7. Example Request Trace

StepActionOutcome
1Client POST /shorten with https://example.com/very/long/pathApp server generates key abc123x, writes to DB, returns https://short.ly/abc123x
2Client GET /abc123xEdge cache miss; app queries Redis, then DB; returns 301 to original URL
3Analytics worker consumes redirect eventIncrements click counter for abc123x
4Repeat redirect within TTLCache hit; no DB lookup; latency < 10 ms

8. Trade-offs

9. Takeaways


Re-authored and RESHADED for the Knowledge Guide. Replaces raster diagrams with a hand-authored SVG flow and adds a concrete request trace.

Named bottlenecks, the 301-vs-302 trade-off, and when not to build this

BottleneckMechanismMitigation
Redirect hot keyOne viral code → single cache key / DB rowCDN/edge cache 301; multi-layer cache
ID generation collisionBase62 hash of URL collisionsCounter+encode (through a keyed permutation, keeping keys unguessable) or hash+retry with salt
Write path DBEvery create is a writeAsync analytics; sync only mapping insert
Cache stampede on expiryPopular key TTL endsSingle-flight; stale-while-revalidate

301 vs 302: 301 permanent → browsers/CDNs cache aggressively (good for stable links; bad if you need click analytics on every hit). 302 temporary → more origin hits, better counting.

When not custom shortener: low volume internal tools — use managed bitly-class or even DB sequence + base62 without distributed design.

Drill ladder

  1. L1: 7-char base62 space size?
  2. L2: Why not MD5 of URL as key alone?
  3. L3: Design counter service without single SPOF.
  4. L4: Analytics pipeline: redirect path must stay <50 ms — how?
🔨 Practice this hands-on — Design TinyURL (URL Shortener) →
Attempt it from an empty file, break it to feel the failure, then defend it under pushback.
🤖 Don't fully get this? Learn it with Claude

Stuck on Designing a URL Shortening Service like TinyURL? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Designing a URL Shortening Service like TinyURL** (System Design) and want to truly understand it. Explain Designing a URL Shortening Service like TinyURL from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Designing a URL Shortening Service like TinyURL** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Designing a URL Shortening Service like TinyURL** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Designing a URL Shortening Service like TinyURL** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes