Skip to content
URL Shortener System Design: The Classic Interview Question 5 min

URL Shortener System Design: The Classic Interview Question

SD
ScaleDojo
May 11, 2026
5 min read1,144 words
3
Cover illustration for URL Shortener System Design: The Classic Interview Question

Bitly: 600 Million Clicks a Month

Bitly: 600 Million Clicks a Month

Bitly shortens around 150 million URLs per month and serves roughly 600 million redirects, a 4:1 read-to-write ratio. Whether you call this problem "design TinyURL" or think of it as URL shortener system design, it's one of the most common warm-up questions in a system design interview, and for good reason. A tiny feature surface hides real decisions about encoding, database design, caching, and global delivery.

Requirements and Estimation

Requirements and Estimation

Start any URL shortener system design interview by pinning down what you're actually building. The functional side is short:

  • Given a long URL, return a short code (commonly 7 characters).

  • Given a short code, redirect the user to the original long URL.

  • Optionally support custom aliases, expiration dates, and click analytics.

The non-functional requirements are where the interesting numbers live:

  • 100 million URLs created per day, which works out to about 1,160 writes per second.

  • A 10:1 read/write ratio, meaning 1 billion redirects per day, or roughly 11,600 reads per second.

  • Redirect latency under 100ms at p99.

  • URLs are never deleted outright, but expire after 5 years.

  • 99.99% availability, about 53 minutes of downtime per year.

From there, estimate storage. Over 5 years at 100 million URLs a day, you get 100M × 365 × 5 ≈ 182.5 billion URL mappings. If each record (short code, long URL, metadata) takes up roughly 500 bytes, total storage comes out to:

182.5 billion records × 500 bytes per record ≈ 91.25 TB.

That's a big number on paper, but it's well within what a single well-sharded relational database or a key-value store can handle over five years, especially since writes are append-heavy and reads dominate.

Encoding Strategies Compared

Tip: whichever encoding scheme you pick, reserve a small blacklist of generated codes up front. Base62 will occasionally spit out something that reads as a slur or an obviously offensive word once decoded, and nobody wants to discover that in production. A simple filter check before you commit a new code to the database is cheap insurance.

The core design question is how you turn a long URL into a short, unique code. A few options come up again and again in interviews, each with a different failure mode.

Method

Collision Risk

Sequential?

Bottleneck

MD5 / SHA-256 hash (truncated)

Yes, needs a collision check

No

None

Base62 counter

No

Yes

The counter itself

Random UUID

Rare, still needs a check

No

None

Snowflake ID

No (guaranteed unique)

Roughly, time-ordered

None

Base62 encoding uses the character set a-z, A-Z, and 0-9, which is 62 symbols. With a 7-character code, that gives you 62^7, or about 3.52 trillion possible codes. At 100 million new URLs a day, you'd burn through that space in roughly 96 years, plenty of headroom for a system that's also retiring URLs after 5 years.

The recommended approach for most answers: generate a Snowflake ID first, then base62-encode it down to 7 characters. This sidesteps the two real problems with a naive counter, no central counter becomes a bottleneck under concurrent writes, and there are no collisions to check for, since the ID is already globally unique. As a bonus, Snowflake IDs are roughly time-ordered, which is handy later if you want to reason about analytics by creation time. An ID like 125834027 base62-encodes into something like 'aB3x7Kq'.

Try it yourself: enter a number and watch it base62-encode into a short code in real time.

Architecture: Write Path and Read Path

Once encoding is settled, the rest of the design splits cleanly into two paths that barely touch each other.

On the write path (about 1,160 requests/sec), a client sends a long URL to an API server, which generates a Snowflake ID, base62-encodes it into a 7-character code, inserts the mapping into the primary database, and returns the short URL. This path is low-volume enough that a single PostgreSQL instance handles it without much drama.

The read path (about 11,600 requests/sec) is where caching earns its keep. A request for a short code hits a CDN edge first; on a cache hit, it returns a 301/302 redirect in under 5ms. On a miss, it falls through to Redis, which if it hits, returns the redirect in under 10ms. Only on a full miss does the request reach PostgreSQL, which looks up the mapping, populates Redis with a 24-hour TTL, and returns the redirect in under 50ms.

In practice, this layered approach means around 99% of the 1 billion daily redirects never touch the database at all. That leaves PostgreSQL handling roughly 11 million reads a day, which is about 127 reads per second, comfortably inside what a single instance can absorb. If you want to go deeper on how to think about TTLs, cache placement, and invalidation trade-offs in a setup like this, it's worth reading through this breakdown of caching strategies.

Click through the write and read paths to see where each request goes and how caching cuts database load.

301 vs 302: The Redirect Trade-off

Watch out: a 301 isn't just cached by the browser, it can get cached by ISPs and corporate proxies too, sometimes for months. If you ever need to change where a short code points (say, a customer wants to update their destination URL), a 301 that's already been cached means some fraction of clicks will never even hit your server to see the update. Once you've shipped a 301, treat that mapping as effectively permanent.

The status code you choose for the redirect is a small decision with a real trade-off attached, and it's worth calling out explicitly in an interview.

Status Code

Browser Behavior

Server Load

Analytics

301 (Permanent)

Cached by the browser indefinitely

Lower, fewer repeat hits

Can't reliably track repeat clicks

302 (Temporary)

Browser re-checks the server every time

Higher, every click hits your server

Full visibility into who clicked and when

If the product needs click analytics, which most URL shorteners do, 302 is the right default even though it costs more server load. If raw redirect performance matters more than tracking, 301 wins.

Interview Tip

Start with requirements and estimation, and show your math out loud: 100 million writes a day is about 1,160 writes per second, which a single PostgreSQL instance handles without issue. For encoding, recommend Snowflake ID plus base62 (no collisions, no counter bottleneck). For reads, layer CDN, Redis, and the database to get a 99%+ cache hit rate. Bring up the 301 vs 302 trade-off unprompted, it signals you understand the analytics implications. This question tests whether you can design a complete system end to end, not just clever encoding.

Key Takeaway

A URL shortener boils down to: generate codes with a base62-encoded distributed ID (not a naive counter), write to a relational database, and serve the vast majority of redirects from CDN and Redis caches. The read path is 99% cache hits by design. Start simple, and only shard writes once the numbers actually demand it. This pattern, encode once, cache-heavy reads forever, shows up in dozens of other interview problems once you know to look for it.

If you're building out a broader interview prep plan beyond this one problem, this comparison of system design learning platforms is a decent starting point for what to practice next.

Enjoyed this article?

Share it with your network to help others level up their system design skills.

Discussion0

Join the Discussion

Sign in to leave comments, reply to others, or like insights.

Sign In to ScaleDojo

No comments yet. Be the first to start the thread!

Related Articles

Enjoyed this content?

Your support keeps us creating free resources

We put a lot of hours into researching and writing these guides. If it helped you, consider buying us a coffee. Every bit goes toward keeping ScaleDojo's content free and growing.

$

One-time payment via Stripe. ScaleDojo account required.

ScaleDojo Logo
Initializing ScaleDojo