System Design Interview · TinyURL / bit.ly

URL Shortener System Design

How to design a URL shortener like TinyURL or bit.ly in a system design interview: requirements, capacity estimates, key generation, 301 vs 302 redirects, caching, sharding and the follow-ups interviewers ask.

Updated 17 October 2026

1Requirements

A URL shortener maps a long URL to a short key and redirects anyone who visits the short link to the original. Start the interview by agreeing what is in scope - candidates who skip this end up designing features nobody asked for.

Functional requirements

  • Given a long URL, return a unique short URL.
  • Visiting the short URL redirects to the long URL.
  • Optional custom aliases, such as /my-launch.
  • Optional expiry: a link stops working after a set time.
  • Basic click analytics per link (count, time, referrer, country).

Non-functional requirements

  • High availability for redirects - a broken redirect breaks every page that embeds the link.
  • Low redirect latency, in the order of tens of milliseconds at the server.
  • Short keys must not be guessable in sequence, so private links cannot be enumerated.
  • Writes can tolerate slightly higher latency than reads.
Say what you are leaving out: user accounts, link editing UI and a full analytics dashboard are usually out of scope. Naming them shows you scoped deliberately.

2Capacity Estimates

A common set of assumptions: 100 million new links a month, a 100:1 read-to-write ratio, links kept for five years, and about 500 bytes per record. The point of the numbers is the conclusion they lead to, so state it.

QuantityCalculationResult
New links (writes)100M ÷ (30 × 86,400 s)≈ 40/s average, ~200/s peak
Redirects (reads)40/s × 100≈ 4,000/s average, ~20,000/s peak
Links over 5 years100M × 12 × 5≈ 6 billion
Storage6B × 500 bytes≈ 3 TB (≈ 9 TB with 3 replicas)
Key length62⁷ ≈ 3.5 trillion vs 6B links7 characters is ample
Cache for hot links20% of a day’s ~346M redirects × 500 bytesUp to ~35 GB - fits a small Redis cluster
Conclusion: the system is read-dominated and the dataset is modest. Redirect latency and availability matter far more than write throughput, so the cache and the read path deserve most of your time.

3API Design

Create a short link
POST /api/v1/urls
{ "long_url": "https://example.com/very/long/path", "custom_alias": "launch", "expires_at": "2027-01-01T00:00:00Z" }

201 Created
{ "short_url": "https://sho.rt/launch", "key": "launch" }
Redirect
GET /{key}

302 Found
Location: https://example.com/very/long/path
  • Return 404 for an unknown key and 410 Gone for an expired one, so crawlers and clients can tell the difference.
  • Return 409 Conflict when a custom alias is already taken.
  • Rate limit the create endpoint per API key or IP; the redirect endpoint usually is not limited per user.

4Data Model and Storage

url_mappings
  key          VARCHAR(16)  PRIMARY KEY   -- the short key
  long_url     TEXT         NOT NULL
  created_at   TIMESTAMP
  expires_at   TIMESTAMP    NULL
  owner_id     BIGINT       NULL

Every read is a lookup by key, and there are no joins. That access pattern fits a key-value or wide-column store such as DynamoDB or Cassandra, which shard and replicate natively. A relational database also works at this size if the key is the primary key - choose based on the operational trade-off you can defend, and say why.

If the same long URL should always return the same short link, add a secondary index on a hash of long_url and check it before creating. Many designs skip this deliberately: deduplication costs an extra read on every write, and different users often want separate links for separate analytics.

5High Level Design

           ┌──────────────┐
 client ──►│ Load balancer│
           └──────┬───────┘
                  ▼
        ┌───────────────────┐   miss   ┌──────────────┐
        │  App servers      │ ───────► │  Key-value   │
        │  (stateless)      │ ◄─────── │  store       │
        └──┬─────────┬──────┘          │  (sharded)   │
           │ hit     │ click events    └──────────────┘
           ▼         ▼
      ┌────────┐ ┌────────┐   ┌───────────────┐
      │ Redis  │ │ Kafka  │──►│ Analytics     │
      │ cache  │ └────────┘   │ aggregation   │
      └────────┘              └───────────────┘
   Key source: leased counter ranges or a key generation service

Write path

  1. The app server validates the URL (scheme, length, malware check).
  2. It takes the next key from its leased range or key batch, or checks a custom alias is free.
  3. It writes the mapping with a conditional insert, so a duplicate key fails instead of overwriting.
  4. It returns the short URL; the cache is filled on first read.

Read path

  1. The app server looks the key up in Redis.
  2. On a miss it reads the store and populates the cache (cache-aside).
  3. It checks expiry, returns the redirect, and publishes a click event to Kafka without waiting.

6Deep Dive: Generating the Short Key

This is the part of the round interviewers probe hardest. There are four common approaches, and the trade-offs between them are the answer.

ApproachHow it worksStrengthsWeaknesses
Hash and truncateMD5 or SHA-256 of the long URL, Base62-encode, keep the first 7 characters.No coordination; the same URL gives the same key.Collisions grow with volume, so every write needs a check-and-retry with a salt.
Counter + Base62A global counter increments; the number is Base62-encoded.Never collides; keys stay short.Sequential keys are guessable, and a single counter is a bottleneck.
Leased counter rangesEach app server leases a block (say 1M IDs) from ZooKeeper or a database, and obfuscates each ID before encoding.No per-write coordination; unique; not guessable after obfuscation.A crashed server wastes the rest of its block - harmless with 3.5T keys.
Key generation serviceA service pre-generates random unused keys; servers fetch batches and mark them used.Random, unique keys with no collision checks at write time.Another service to run, and it must never hand out the same key twice.

Obfuscation means passing the sequential ID through a reversible shuffle before Base62 encoding - for example multiplying by a large number coprime with 62⁷ modulo 62⁷, or a small Feistel network. The mapping stays one-to-one, so uniqueness is preserved, but consecutive IDs no longer produce neighbouring keys.

Why not Snowflake IDs? They are unique without coordination, but a 64-bit ID encodes to about 11 Base62 characters, not 7, and because the IDs are time-ordered, keys created together look alike. They solve uniqueness but not shortness or guessability.

Custom aliases

  • Insert with a conditional write (put-if-absent or a unique constraint) and return 409 if it fails - never check-then-write, which races.
  • Reserve words that collide with your own routes (api, admin, login) and enforce a character set and maximum length.
  • Keep custom aliases out of the generated key range, for example by a minimum length or a distinct prefix, so they never collide.

7Deep Dive: 301 vs 302 Redirects

301 Moved Permanently302 Found (or 307)
Browser cachingBrowsers cache it and may skip your server on repeat visits.Browsers ask your server every time.
AnalyticsYou see the first click per browser, not every click.Every click reaches you.
Changing the destinationHard - cached copies keep the old target.Easy - the next visit gets the new target.
Server loadLower.Higher, which the cache absorbs.

Pick based on the requirements you agreed: if per-click analytics or editable links are in scope, use 302. If the priority is raw speed and load, 301 is defensible. Either answer is fine when you tie it back to a requirement - choosing without a reason is what loses marks.

8Scaling, Caching and Sharding

Cache-aside with Redis

Cache key → long URL with an LRU eviction policy and a TTL no longer than the link expiry. Popular links are a small fraction of all links, so a modest cache serves most redirects.

Shard by key

Partition the store by a hash of the short key using consistent hashing, so adding nodes moves only a fraction of keys. Lookups always include the key, so every read hits exactly one shard.

Replicate for reads

Keep replicas in each region and serve redirects from the nearest one. Short replication lag is acceptable: a link created a second ago is rarely clicked in that second, and the write region can serve misses.

Hot keys

A viral link can concentrate traffic on one cache node. Replicate hot keys across cache nodes, keep a small in-process cache on app servers, or cache the redirect at the CDN edge with a short TTL.

Async analytics

Publish a click event to Kafka and return the redirect immediately. Consumers aggregate counts per link and time bucket into an analytics store, so a slow analytics pipeline never delays a redirect.

Expiry and cleanup

Check expires_at on read and return 410, then remove expired rows with a background job. Lazy checks keep reads correct even before the cleanup runs.

9Failure Modes and Security

What failsImpactMitigation
Cache clusterEvery redirect falls through to the store, which may not take 20,000 reads/s.Replicated cache, read replicas sized for a cold cache, request coalescing for the same key.
Key source (ZooKeeper or key service)New links cannot get keys.Servers hold a leased range or batch, so they keep creating links until it runs out.
A storage shardLinks on that shard fail to resolve.Replication with automatic failover; serve from replicas.
A regionRedirects fail for users routed there.Multi-region replicas and DNS or anycast failover.

Abuse and security

  • Scan URLs against a malware and phishing list before creating them, and keep a way to disable a link.
  • Rate limit link creation per account and IP so the service is not used to mass-produce spam links.
  • Never use sequential keys without obfuscation: guessable keys expose private links such as shared documents.
  • Validate the scheme (http or https only) to avoid javascript: or data: URLs being served as redirects.

The 45-Minute Interview Walkthrough

  1. 0-5

    Clarify requirements

    Core features, custom aliases, expiry, analytics, and what is out of scope.

  2. 5-10

    Estimate

    Writes, reads, storage and key length - then state that the system is read-heavy.

  3. 10-15

    API and data model

    Create and redirect endpoints, status codes, and the key-value record.

  4. 15-25

    High level design

    Load balancer, stateless servers, cache, store, key source and analytics queue.

  5. 25-40

    Deep dive

    Usually key generation, then caching and sharding. Compare approaches and pick one with a reason.

  6. 40-45

    Failure and wrap-up

    What breaks first, how you would detect it, and what you would build next.

Follow-Up Questions Interviewers Ask

How do you stop people guessing other short links?

Do not expose sequential keys. Either obfuscate the counter with a reversible shuffle before encoding, or use random keys from a key generation service, and keep the key long enough that random guessing is impractical.

What happens if two users shorten the same long URL?

By default they get different keys, which keeps their analytics separate. If deduplication is a requirement, index a hash of the long URL and return the existing key.

How would you handle 10x the traffic?

Redirects scale horizontally: more stateless servers, more cache nodes and more read replicas. Writes are still only a few thousand a second at 10x, which leased key ranges handle without a central bottleneck.

How do you let users edit or delete a link?

Update or delete the row and invalidate the cache entry. This is one reason to prefer 302 redirects - a 301 may already be cached in browsers with the old target.

How do you count clicks without slowing redirects?

Emit an event to a queue after sending the redirect and aggregate counts in a separate consumer. Approximate real-time counts can come from a counter in Redis, reconciled from the event log.

Can you reuse expired keys?

You can return them to the key pool, but old links may still be printed or bookmarked and would now point somewhere new. With 3.5 trillion keys available, most designs never reuse them.

FAQ

Is a URL shortener a good system design interview question?

Yes. It is one of the most common first system design questions because it is small enough to finish in 45 minutes while still testing estimation, key generation, caching, sharding and trade-offs.

How long should the short key be?

Seven Base62 characters give about 3.5 trillion combinations, which is ample for billions of links. Six characters give about 56.8 billion - enough for many systems, but with less headroom.

Is designing TinyURL the same as designing a URL shortener?

Yes. "Design TinyURL", "design bit.ly" and "design a URL shortening service" are the same question with different names.

Should I use a hash of the URL as the short key?

Truncated hashes collide as the dataset grows, so every write needs a collision check and retry. Leased counter ranges with obfuscation, or a key generation service, avoid collisions entirely and are the stronger answer.

SQL or NoSQL for a URL shortener?

Either can work. The access pattern is a simple lookup by key with no joins, which suits key-value stores that shard natively, but a relational database with the key as primary key is fine at this scale. Justify the choice with your estimates.

Should a URL shortener use 301 or 302 redirects?

Use 302 when click analytics or editable destinations are requirements, because browsers ask your server on every visit. Use 301 when speed and lower load matter more, accepting that browsers may cache the redirect.

Where can I practise this question?

You can practise the URL shortener question free on InstaMock with an AI interviewer that asks for your requirements and estimates, probes your key generation and caching choices, and gives scored feedback.

Practise It Out Loud

Reading a design is not the same as defending one. Book a live 1:1 round with an engineer who has taken hiring decisions: they ask the follow-ups, push on the weak parts, and send written feedback.

Book a 1:1 Mock Interview - ₹499

Not ready yet? Practise this question free with the AI interviewer