System Design Blueprint

Building a URL Shortener

An original guide on engineering a link shortening service like TinyURL from scratch. Discover the architecture, core logic, and scaling strategies for a production-ready system.

1Defining the Scope

A solid design starts with clear goals and an understanding of the expected load.

At its core, a URL shortener transforms a lengthy web address into a much shorter, more manageable link. When a user accesses this condensed link, the service seamlessly redirects them to the original destination.

Core Features (Functional)

  • → Convert a long URL into a short one.
  • → Forward users from the short URL to the original.
  • → Optionally, allow users to name their own links.
  • → Links should be able to expire after a set time.

Performance Goals (Non-Functional)

  • Uptime: The service must be extremely reliable.
  • Speed: Redirects need to feel instantaneous.
  • Throughput: It must support heavy traffic.
  • Security: The generated links shouldn't be predictable.

Traffic & Storage Estimates

Hypothetical Load:

  • • Writes: 100 million new links are created monthly.
  • • Reads: Each new link is read 100 times on average (100:1 read/write ratio).
  • • Lifespan: We store links for 5 years.

Performance Needs:

100M / (30d × 24h × 3600s) ≈ 40 writes/sec

40 writes/sec × 100 = 4,000 reads/sec

100M × 12m × 5y × 500 bytes ≈ 3 Terabytes

Primary Takeaway: The system is overwhelmingly read-dominant. Optimizing for fast reads through caching is the most critical performance consideration.

2High-Level Blueprint

Let's define our service's contract (API) and outline the flow of data.

Service API

POST /api/v1/shorten

Body: { "long_url": "...", "custom_alias": "..." }

Response: { "short_url": "..." }

GET /{short_url}

HTTP Status: 302 Found

Header: Location: {long_url}

Architectural Flow

The system's operation can be separated into two primary sequences: the "write path" for creating links and the "read path" for handling redirects.

Write Path (Creating a Link):

1. A user sends the long URL to our service.

2. A dedicated ID Generator produces a globally unique number.

3. This number is encoded into a short string (the path for our URL).

4. This new mapping (short string → long URL) is written to the Database.

Read Path (Redirecting a Link):

1. A user clicks a short link, hitting our service.

2. The service immediately checks a high-speed Cache.

3. If it's a popular link (a cache hit), we redirect instantly. If not (a cache miss), we query the main Database.

4. The service sends an HTTP redirect back to the user's browser.

3Detailed Component Design

Generating Keys with Base62

A robust method for creating non-colliding, non-sequential, short keys is to pair a distributed unique ID generator with Base62 encoding. Think of it as converting a very large number into a compact, URL-friendly string.

1. Request a unique 64-bit integer from a service like Snowflake (e.g., `1000123456789`).

2. Treat this integer as a number in base-10 and convert it to base-62.

Our "digits" are now the 62 characters: `0-9`, `a-z`, and `A-Z`.

3. The result of this conversion is a short, URL-safe string like `p4J3j2a`.

✓ Strengths:

  • • Guarantees uniqueness, no collisions.
  • • Scales horizontally with the ID generation service.
  • • Resulting URLs are not predictable.

✗ Weakness:

  • • Introduces a dependency on a separate ID service.

The Redirect: Permanent vs. Temporary

301 Redirect (Permanent)

Instructs the browser to remember this redirect forever. On future visits, the browser won't even contact our server.

✓ Benefit: Fastest possible experience for repeat visitors.

✗ Drawback: We lose all visibility. No analytics, no ability to edit the link.

302 Redirect (Temporary)

Tells the browser that the link is only valid for now. The browser must check with our server every time.

✓ Benefit: Enables click tracking, A/B testing, and editing the destination.

✗ Drawback: Incurs a small latency penalty for the extra network hop.

Our Choice: A 302 redirect is standard for this use case because the ability to gather analytics is a core business requirement.

Data Storage

While a simple key-value store is a natural fit, a standard relational database also works perfectly. The key is efficient retrieval. We must ensure the `short_url` column is the primary key and indexed for lightning-fast lookups.

Table: url_mappings
    ├── short_url     VARCHAR(7)   PRIMARY KEY
    ├── long_url      TEXT
    ├── created_at    TIMESTAMP
    └── expires_at    TIMESTAMP    NULLABLE

4Refinements and Scaling

Caching Layer

With reads dominating traffic, a cache is non-negotiable. Storing `short_url` -> `long_url` pairs in an in-memory cache like Redis will serve the majority of requests without touching the database. A "Least Recently Used" (LRU) policy will ensure the most popular links stay in the cache.

Rate Limiting

To protect our service from malicious actors or runaway scripts, we must limit how many URLs a single user or IP address can create in a given time frame. This prevents system overload and ensures fair usage.

Analytics Collection

Recording every click can slow down redirects. To solve this, the redirect handler should immediately send the user on their way and then, in a "fire-and-forget" manner, publish the click event to a message queue (e.g., Kafka). Downstream services can then process these events for analytics without impacting user-facing latency.

Database Partitioning

When our data (terabytes) outgrows a single machine, we must partition it (shard). By splitting the data based on a hash of the short URL, we can distribute storage and query load across an entire fleet of database servers, allowing for near-infinite horizontal scaling.

Final Design Principles

  • Design for reads: An aggressive caching strategy is paramount for a read-heavy system.
  • Guarantee unique links: Use a distributed ID generator with Base62 encoding to prevent collisions and scale writes.
  • Enable analytics: Prefer 302 temporary redirects to maintain visibility into link performance.
  • Protect the service: Implement strict rate limiting to prevent system abuse.
  • Keep redirects fast: Offload secondary tasks like analytics to an asynchronous message queue.

Ready to Practice?

Practice designing a URL Shortener with an AI interviewer and get instant feedback.

Related System Design Questions: