system-design · intermediate
Design a URL Shortener — Interview Walkthrough
Start here
A URL shortener turns a long link into a short one:
https://news.example.com/articles/2026/07/very-long-title...
→ https://sho.rt/aB3xY9
When users open the short link, the service redirects them to the original URL (usually HTTP 301/302).
This is a classic system design interview because it touches APIs, data modeling, hashing, caching, scale, and abuse—without requiring exotic domain knowledge.
What you will learn
- Clarify requirements like an interview.
- Estimate traffic with back-of-the-envelope math.
- Design write and read paths.
- Choose short-code generation strategies.
- Scale reads with cache and partitions.
- Cover analytics, expiry, and abuse at a practical level.
What you should know first
| Topic | Why |
|---|---|
| System design foundations | Structured design approach |
| Answering framework | Interview flow |
| Caching 101 | Hot redirect path |
| HTTP redirects | 301/302 behavior |
Words you need before we begin
| Term | Plain English |
|---|---|
| Short code | The aB3xY9 path segment. |
| Redirect | Response telling the browser to go to another URL. |
| 301 vs 302 | Permanent vs temporary redirect (caching differs).
| Base62 | Encoding using 0-9, A-Z, a-z (62 symbols). |
|---|---|
| Collision | Two URLs mapped to the same short code. |
| Idempotent create | Creating the same long URL twice can return the same code. |
| Hot key | Extremely popular short link receiving huge read QPS. |
Simple story: coat check
You hand a long coat (long URL) and get a small ticket number (short code). Later you present the ticket and get the coat. The attendant’s binder is the database; a memo on the desk for today’s popular tickets is the cache.
Requirements (ask first)
Functional
- Create short URL from long URL (auth optional).
- Redirect short → long.
- Optional: custom alias, expiry, click counts.
Non-functional
- Redirects are read-heavy, low latency.
- High availability for redirects.
- Durability for mappings.
- Abuse resistance (spam, malware links).
Example scale (state assumptions)
- 100M new links/month ≈ ~40 writes/s average (burst higher).
- Read:write 100:1 → thousands of redirects/s.
- Store 5 years of links → billions of rows possible—plan growth.
High-level design
flowchart LR
U[User] --> API[API / redirect service]
API --> C[(Cache)]
API --> DB[(Mapping DB)]
API --> Gen[Code generator]
- Write path: validate URL → generate code → persist mapping → return short URL.
- Read path: lookup code in cache → else DB → cache → HTTP redirect.
Step-by-step core design
Step 1 — API sketch
POST /api/v1/linksbody{"longUrl":"..."}→{"shortUrl":"https://sho.rt/aB3xY9"}GET /{code}→302 Location: longUrl
Step 2 — Code generation options
| Approach | Idea | Trade-off |
|---|---|---|
| Hash + truncate | Hash long URL, encode | Collisions; same URL same code if careful |
| Counter + Base62 | Global/range counters encoded | Needs coordinated counter ranges |
| Random 64-bit | Random then insert | Collision retry; simple |
Interview-friendly: pre-allocated counter ranges per instance + Base62, or random with unique DB constraint.
Step 3 — Data model
Table links(code PK, long_url, created_at, owner_id, expires_at, click_count).
Unique on code. Optionally unique on hash of long URL for dedupe.
Step 4 — Redirect performance
- Cache code → long_url in Redis with TTL.
- 301 for permanent (CDN/browser cache) vs 302 if links can change—product choice.
- Keep redirect service stateless behind load balancer.
Step 5 — Scale writes
- Shard by code prefix or hash of code.
- Separate write API from ultra-hot redirect tier if needed.
Step 6 — Analytics
Do not do heavy analytics on the redirect path. Emit async click event to a queue/stream.
Step 7 — Abuse
- Auth or rate limit creation.
- Malware URL scanning async.
- CAPTCHA when suspicious.
Complete worked example: MVP → scale
Starting situation
Startup expects 1M links and 100 redirects/s peak next year.
Decisions
| Layer | MVP | Later |
|---|---|---|
| DB | Single Postgres | Sharded by code |
| Cache | Redis | Multi-AZ Redis |
| Codes | 8-char Base62 random + unique | 7–8 chars with capacity planning |
| Analytics | Daily batch | Stream + warehouse |
Failure modes in discussion
- DB down: redirects may still work from cache for hot keys; creates fail.
- Cache stampede on viral link: single-flight load + high TTL.
- Collision: retry generation.
How interviewers score you
- Clarified scope and scale
- Separated read/write paths
- Concrete data model
- Named bottlenecks (redirect QPS, storage growth)
- Trade-offs (301 caching vs control)
- Not only buzzwords
Failure modes
| Mode | Impact | Mitigation |
|---|---|---|
| Hot short link | Hot partition/CPU | Cache, CDN edge, replicate |
| Exhausted code space | Create failures | Longer codes; capacity math |
| Open redirect abuse | Reputation risk | Allowlist schemes; scan |
| Sync analytics on path | Latency spikes | Async events |
| No uniqueness on code | Wrong redirects | Primary key + tests |
Trade-offs
| Choice | Benefit | Cost |
|---|---|---|
| 301 permanent | Fast client-side cache | Harder to change target |
| 302 temporary | Control | More origin hits |
| Dedupe long URLs | Fewer rows | Privacy/complexity |
| Custom aliases | Product feature | Abuse, uniqueness fights |
Common misunderstandings
- “MD5 the URL and take six chars—done.” Collisions and predictability.
- “Put everything in one huge Redis forever.” Memory cost; still need durable store.
- “Global lock for counter.” Becomes a bottleneck—use ranges.
- “Redirect must update click count synchronously.” Prefer async.
- “Sharding is day one.” Start simpler; show evolution path.
Check your understanding
- What are the two primary APIs?
- Why is the system read-heavy?
- Name two code generation strategies.
- Why cache redirects?
- How should click analytics run?
Practice
- Compute how many 7-character Base62 codes exist roughly.
- Draw sequence for create and redirect with cache miss.
- Design rate limits for anonymous creates.
- Plan migration from one DB to sharded storage.
- Mock a 30-minute interview aloud with a timer.
Deeper production notes
Character set
Avoid ambiguous characters if humans type codes (0/O, 1/l). Product decision vs pure density.
GDPR and deletion
Deleting a mapping may be required; caches and CDN must honor invalidation. 301s cached by browsers are sticky—another reason some products prefer 302.
Multi-region
Redirects benefit from geo DNS + regional caches. Creates can be region-primary with async replication of mappings.
Additional teaching scenarios
Scenario A — peak load day
Traffic multiplies by ten. Re-read the failure modes and mark which appear first. Write the first mitigation for each.Scenario B — mixed versions
Half the fleet runs the old build. Which assumptions break if protocols or schemas disagree? Prefer designs that tolerate one deploy window of mixed versions.Scenario C — five-sentence teach-back
Explain the core idea without acronyms. If you cannot, revisit the simple story and worked example.Scenario D — metrics and alerts
List three metrics and one alert threshold that name user impact or a resource that runs out.Scenario E — non-goals
Write two problems this technique should **not** solve, to prevent cargo-cult adoption.Scenario F — ownership
Name who owns dashboards, code changes, and pages. Blank ownership means the feature is not ready for broad enablement.Revision summary
- Shortener = create mapping + fast redirect.
- Design API, encoding, storage, cache, abuse.
- Optimize reads; keep analytics off the hot path.
- Show scale evolution and honest trade-offs in interviews.
Glossary
| Term | Definition |
|---|---|
| Short code | Compact identifier in the short URL path. |
| Base62 | Encoding alphabet of 62 alphanumeric chars. |
| Redirect | HTTP response sending the client to another URL. |
Abbreviations and terminology
- QPS — Queries per second
- CDN — Content Delivery Network
- PK — Primary key
- TTL — Time to live
What to learn next
Extra teaching notes for first-time builders
Write the single bottleneck you are protecting before picking tools. Name the signal that tells you the design is working for users, not only that internal counters move. When reviewing a change related to this lesson, ask what happens when the component is slow for ten minutes, down entirely, or running twice. Prefer small explicit failure modes that operators can understand at 3 a.m.
Document ownership for dashboards, code, and pages. Undocumented mechanisms become folklore and then outages. Prefer designs that tolerate mixed versions for at least one deploy window so rollouts do not require perfect global simultaneity.
Napkin math helps: estimate peak rate, multiply by payload size, and ask whether the design still holds when a dependency is at half capacity. If the answer depends on luck, add bounds, backpressure, or shedding before production traffic arrives.
Extra teaching notes for first-time builders
Write the single bottleneck you are protecting before picking tools. Name the signal that tells you the design is working for users, not only that internal counters move. When reviewing a change related to this lesson, ask what happens when the component is slow for ten minutes, down entirely, or running twice. Prefer small explicit failure modes that operators can understand at 3 a.m.
Document ownership for dashboards, code, and pages. Undocumented mechanisms become folklore and then outages. Prefer designs that tolerate mixed versions for at least one deploy window so rollouts do not require perfect global simultaneity.
Napkin math helps: estimate peak rate, multiply by payload size, and ask whether the design still holds when a dependency is at half capacity. If the answer depends on luck, add bounds, backpressure, or shedding before production traffic arrives.
Extra teaching notes for first-time builders
Write the single bottleneck you are protecting before picking tools. Name the signal that tells you the design is working for users, not only that internal counters move. When reviewing a change related to this lesson, ask what happens when the component is slow for ten minutes, down entirely, or running twice. Prefer small explicit failure modes that operators can understand at 3 a.m.
Document ownership for dashboards, code, and pages. Undocumented mechanisms become folklore and then outages. Prefer designs that tolerate mixed versions for at least one deploy window so rollouts do not require perfect global simultaneity.
Napkin math helps: estimate peak rate, multiply by payload size, and ask whether the design still holds when a dependency is at half capacity. If the answer depends on luck, add bounds, backpressure, or shedding before production traffic arrives.
FAQ from first-time learners
Q: How long should codes be?
A: Long enough for capacity and unpredictability; interview with math, not a fixed magic number.
Q: SQL or NoSQL?
A: Both work; justify access patterns (lookup by code is key-value-like).
Q: Do I need Kafka?
A: Only if you justify analytics/stream needs—not as decoration.
Track: Distributed Systems
Previous: Rate Limiting Algorithms — Token Bucket, Windows, and Bursts
By Shubham Jain