The System Design Interview: A Step-by-Step Framework
A step-by-step framework for system design interviews: clarifying requirements, estimates, APIs, data models, high-level design, deep dives and trade-offs.
A URL shortener system design: requirements, capacity estimates, API, short-code generation, database choice, caching, analytics and scaling trade-offs.

The URL shortener is the classic warm-up system design problem because it’s small enough to finish in an interview but touches the fundamentals: ID generation, storage, caching and scale. We’ll follow our system design interview framework.
Functional: create a short link for a long URL; redirect short links to the original; optional custom aliases and expiry.
Non-functional: redirects must be fast (low tens of milliseconds) and highly available; links must never collide or change destination.
Assume 100 million new links a month:
Conclusion: a read-heavy system where caching dominates.
POST /api/links { "url": "https://example.com/very/long", "alias": null, "expiresAt": null }
-> 201 { "code": "a8Xk2Q", "shortUrl": "https://sho.rt/a8Xk2Q" }
GET /{code} -> 301 or 302 redirect
Use 301 if links never change and you want browsers to cache the redirect; use 302 if you need every click to reach your servers for analytics.
Option A: counter + base62. A distributed ID generator issues unique integers; encode them in base62 (a–z, A–Z, 0–9). Seven characters give 62^7 ≈ 3.5 trillion codes. Codes are short and never collide, but they are sequential and guessable.
Option B: random codes. Generate random 7-character strings and check for collisions on insert. Harder to guess; needs a uniqueness check.
Option C: hash the URL. Take a hash and truncate it. Deterministic, but collisions must still be handled.
Most designs choose A with a small random component, or B.
A single table: code (primary key), long URL, created time, expiry, owner. Access is a pure key lookup, which suits a key-value or wide-column store; a relational database with an index works well at moderate scale. See SQL vs NoSQL for the trade-offs, and database sharding for when a single node isn’t enough.
Clients → load balancer → stateless app servers → cache → database. Popular links sit in a cache using the cache-aside pattern. A small number of links receive most traffic, so a modest cache absorbs the majority of reads.
Don’t write to the database on every click. Publish click events to a queue and aggregate them asynchronously. Our comparison of Kafka, RabbitMQ and SQS covers the options.
Apply rate limiting to link creation, scan submitted URLs against malware lists, and expire abandoned links.
Six or seven base62 characters is typical, giving billions to trillions of combinations.
301 is cacheable and faster for users; 302 keeps every click visible to your servers. Choose based on whether you need analytics.
Use a unique counter-based ID, or check for existing codes on insert and retry.
Every article is edited by a human and checked against our editorial policy. Spotted a mistake? Tell us.
A step-by-step framework for system design interviews: clarifying requirements, estimates, APIs, data models, high-level design, deep dives and trade-offs.
Microservices or a monolith? The real costs and benefits of each, the modular monolith middle ground, and a practical framework for deciding and migrating.
How to design a notification system for push, email and SMS at scale: requirements, architecture, queues, templates, preferences, retries and deduplication.