---
title: Designing a Scalable URL Shortener: System Design Walkthrough
siteUrl: https://logzly.com/codeinterviewlab
author: codeinterviewlab (Code Interview Lab)
date: 2026-06-16T15:22:08.894314
tags: [urlshortener, systemdesign, codinginterview]
url: https://logzly.com/codeinterviewlab/designing-a-scalable-url-shortener-system-design-walkthrough
---


Ever tried to share a link that’s longer than a novel?  In interviews you’ll often see “design a URL shortener” because it forces you to think about data modeling, high‑throughput reads, and graceful scaling.  It’s also a great way to show you can balance simplicity with robustness—exactly the kind of skill hiring managers love. A solid grasp of fundamental data structures—such as [binary search trees](/codeinterviewlab/mastering-binary-search-trees-a-step-by-step-guide-for-interview-success)—can also set you apart in system‑design discussions.

## The Problem in Plain English

A URL shortener takes a long web address (like `https://example.com/articles/2024/06/15/how-to-build-a-scalable-service`) and returns a short alias (like `https://sho.rt/abc123`).  When a user clicks the short link, the service must redirect them to the original URL quickly and reliably.

Key goals:

* **Low latency redirects** – users expect an instant jump.
* **High write throughput** – every new short link is a write.
* **Durable storage** – never lose a mapping.
* **Scalability** – handle millions of URLs and billions of redirects.
* **Collision resistance** – two different URLs should not end up with the same short code.

## Core Requirements and Constraints

| Requirement | Why it matters |
|-------------|----------------|
| **Functional** | Store mapping, generate short code, redirect. |
| **Non‑functional** | < 100 ms redirect latency, 99.99 % availability, horizontal scalability. |
| **Assumptions** | Read‑heavy traffic (≈ 90 % redirects, 10 % creates). |
| **Future** | Custom aliases, analytics, expiration. |

In an interview you can state these assumptions explicitly; it shows you’re thinking beyond the obvious.

## High‑Level Architecture

```
Client → API Gateway → URL Service (Create) → DB
Client → CDN Edge → Cache → URL Service (Read) → DB → Redirect
```

* **API Gateway** – single entry point, handles auth, rate limiting.
* **URL Service** – core business logic (code generation, lookup).
* **Database** – durable store for mappings.
* **Cache/CDN** – serves the hot redirects from the edge.
* **Message Queue** (optional) – decouples write path for analytics or batch jobs.

I built a tiny version of this for a personal project last year.  I started with a single Node.js server and a MySQL table, and it survived a few hundred requests per day.  When the traffic spiked during a conference, the latency jumped and the server crashed.  That experience taught me the value of separating reads from writes early on.

## Data Model: Keep It Simple

A single table is enough for the MVP:

```
CREATE TABLE url_mapping (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    short_code VARCHAR(8) UNIQUE NOT NULL,
    long_url TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```

* **short_code** – the key that appears in the short URL.  Eight characters gives 62^8 ≈ 2.2 × 10^14 possibilities, more than enough.
* **long_url** – stored as text to accommodate any length.
* **id** – optional, useful if you want to generate codes sequentially.

### Generating the Short Code

Two common approaches:

1. **Hash‑based** – compute a hash of the long URL, then base‑62 encode a slice.  Fast, but collisions are possible; you need a retry loop.
2. **Counter‑based** – use an auto‑incrementing ID, encode it in base‑62.  Guarantees uniqueness, but reveals the total count (usually fine).

In interviews, I prefer the counter method because it’s deterministic and easy to explain.  You can still add a random salt to the ID before encoding if you want to hide the sequence.

## API Design

* **POST /shorten** – body `{ "url": "https://..." }` → returns `{ "shortUrl": "https://sho.rt/abc123" }`.
* **GET /{code}** – redirects (302) to the stored long URL.

Keep the contract minimal; extra features (custom aliases, expiration) can be layered later.

## Scaling Reads: The Real Bottleneck

Redirects dominate traffic, so they must be cheap.  Two tricks make a big difference:

### 1. Edge Caching with a CDN

Push the short‑code → long‑URL mapping to a CDN (e.g., CloudFront, Cloudflare).  The CDN can serve the redirect directly, bypassing your service entirely.  You only need to invalidate the cache when a mapping changes (rare for a shortener).

### 2. In‑Memory Cache

A distributed cache like Redis or Memcached sits between the CDN and the database.  On a cache miss, the service fetches from the DB, stores the result, and returns the redirect.  Subsequent hits are served in microseconds.

## Scaling Writes: Keep It Light

Write traffic is modest, but you still want it to be reliable.

* **Sharding** – split the URL table by short_code hash across multiple DB instances.  This spreads the load and avoids a single point of failure.
* **Asynchronous Persistence** – you can write the mapping to a fast key‑value store first, then replicate to a durable store (e.g., MySQL, Cassandra) via a background worker.  This reduces latency for the user creating the short link. If you want to brush up on tree‑based algorithms before tackling sharding logic, consider reviewing a [concise guide on binary search trees](/codeinterviewlab/master-binary-search-trees-for-coding-interviews-a-30-minute-hands-on-guide).

## Handling Collisions

Even with a counter, you might run into a rare edge case if you ever reset the counter (e.g., after a disaster recovery).  A simple retry loop works:

```
while true:
    code = encode(counter++)
    if db.insert_if_not_exists(code, url):
        break
```

If you use a hash, you need a fallback strategy: append a random salt and re‑hash until you find a free slot.

## Trade‑offs and What to Emphasize in an Interview

| Choice | Pro | Con |
|--------|-----|-----|
| Counter‑based IDs | Simple, guaranteed unique | Predictable URLs |
| Hash‑based IDs | Obscure, no DB round‑trip for generation | Possible collisions |
| Single DB | Easy to reason about | Hard to scale reads |
| Sharded DB + Cache | Scales horizontally | More operational complexity |
| CDN edge redirects | Near‑zero latency | Cache invalidation logic |

When the interviewer asks “what would you improve?”, mention analytics (track click counts), custom aliases, expiration policies, and security (prevent phishing by scanning URLs).  Showing that you can think beyond the core design scores points.

## A Quick Recap (Without the Boring Bullet List)

Start with a tiny service: generate a short code using a counter, store it in a single table, and expose two endpoints.  Add a Redis cache to speed up redirects, then push the mapping to a CDN for edge delivery.  If traffic grows, shard the DB by short code hash and use a message queue to offload analytics.  Throughout, keep the API simple and the data model lean—complexity is the enemy of reliability.

Designing a URL shortener is a perfect micro‑project to practice system design fundamentals: you touch storage, caching, load balancing, and fault tolerance in a single, easy‑to‑understand domain.  Next time you see that classic interview prompt, walk the interviewer through the steps above and you’ll have a solid, interview‑ready answer.