DEV Community

Cover image for Design TinyURL
Piyush Deshmukh
Piyush Deshmukh

Posted on • Originally published at piyushdeshmukh.hashnode.dev

Design TinyURL

Introduction

A URL Shortener service takes a long URL (like https://example.com/some/very/deep/path) and produces a much shorter alias (like https://short.ly/aBcD12). Users accessing the short URL are redirected to the original long URL. Examples include TinyURL, Bitly, etc.

Functional Requirements

Features

  • Shorten a long URL

  • Redirect from Short URL → Long URL

  • Analytics

Users

  • 100M DAU (daily active users)

  • 100:1 read to write ratio

  • 1M writes/day

  • 500 bytes each entry size

  • Data retention for 5 years

Non-Functional Requirements

  • High Availability - The system should be available 24/7, minimal downtime.

  • Low Latency - Redirects should be very fast (~200 ms).

  • High Durability - Data must persist even if servers crash.

API Endpoints

  • POST /api/urls/shorten

    Request Body:

    {
      "longUrl": "https://example.com/some/very/deep/path"
    }
    

    Response Body:

    {
      "shortUrl": "https://short.ly/aBcD12"
    }
    
  • GET /:shorturl

    Response Body:

    {
        "longUrl": "https://example.com/some/very/deep/path"
    }
    

High Level Design

Initial Design for URL Shortening Service

Initial flow for a URL Shortening service will have:

  1. Client sends a URL to shorten

    • The client sends a POST request to the API Gateway, including the original long URL.
  2. API Gateway Forwards to URL Shortening Service

    • The API Gateway routes the request to the URL Shortening Service.
    • This service:
      • Generates a shortCode
      • Saves the mapping (shortCode → longUrl) in the database
      • Returns the short URL to the client (e.g., https://short.ly/abc123)
  3. Client Uses the Short URL

  4. API Gateway Routes to URL Redirection Service

    • The Redirection Service looks up the short code (abc123) in database.
  5. Redirect to Original URL

    • Once the long URL is retrieved, the service responds with a 301 or 302 redirect to the original long URL.
    • The browser follows this redirect and loads the long URL.

Optimize Design & Deep Dives

  1. How will someone be redirected to original url when clicked on short url?

    • When someone clicks on short url, the URL Redirection Service finds corresponding short url in DB.
    • And responds with an HTTP 302 status code (or 301), along with the Location header:

      HTTP 302 Found
      Location: https://www.example.com/very/long/path?ref=campaign
      
  2. Why use 302 (Found) instead of 301 (Moved Permanently)?

    • 302 is Temporary:
      • Tells browsers - "This redirect might change later. Don't cache it permanently."
    • 301 is Permanent:
      • Tells browsers and search engines: "This link will always go to the same place."
      • Browsers will cache it permanently.
  3. Why use NoSQL DB for a URL Shortener?

    • URL shorteners are a perfect fit for NoSQL because they involve simple key-value lookups. For example, you just need to map shortCode → longUrl, which doesn’t require complex joins or relationships.
    • NoSQL offers:

      • High read/write throughput
      • Schema flexibility (you can add tracking data later)
      • Horizontal scalability (easily handle millions of requests)
      • Low-latency key-based access
    • We can use a highly available DB (eg, DynamoDB or Cassandra) to persist mappings

  4. What data should we store in the DB?

    • URL

      {
        "shortCode": "abc123",
        "longUrl": "https://www.example.com/very/long/article?id=12345",
        "createdAt": "2025-09-14T10:00:00Z",
        "userId": "77a211ff"
      }
      
  • User

        {
           "userId": "77a211ff",
           ....
        }
    
  1. As we know URL Shortener is Read heavy, so how can we optimize our system?

    • Add a Caching Layer (eg. Redis)

      • Cache popular shortCode → longUrl mappings
      • Reduces database reads and latency
      • Use TTL or LRU eviction policy to manage memory
    • Use indexing on shortcode in DB

      • Ensure the DB has a proper index on shortcode field.
      • Speeds up lookup queries for redirection.
  2. How to generate unique IDs for each long url?

    Generating unique, collision-free short codes is critical to the URL shortener’s design. Here are the most common methods:

    1. Auto-Incrementing Counter + Base62 Encoding

      • Use a global counter that increments for each new URL.
      • Convert the counter number to Base62 (0-9, A-Z, a-z) to get a short, URL-friendly string.
      • Example: 125 → "cb"
      • Pros:

        • Simple, predictable, no collisions.
        • Very short codes.
      • Cons:

        • Needs centralized counter (hard to scale).
        • Sequential URLs can reveal traffic volume.
    2. Random String with Collision Check

      • Generate a random Base62 string of fixed length (eg., 6 chars).
      • Check the database for collisions, regenerate if exists.
      • Pros:

        • Easy to scale horizontally.
        • Hard to guess next short code (better privacy).
      • Cons:

        • Small collision risk (can be minimized by length).
        • Requires DB check on every generation.
    3. Hashing the Long URL

      • Hash the original URL (MD5/SHA) and use first N chars as short code.
      • Same long URL always gets same short code.
      • Pros:

        • Idempotent (no duplicates for same URL).
        • No centralized state needed.
      • Cons:

        • Collision risk.
        • Slightly longer or less friendly codes.
    4. UUID or GUID Encoding

      • Generate a UUID, encode in Base62 or hex.
      • Use a substring as the short code.
      • Pros:

        • Globally Unique.
      • Cons:

        • Codes are longer.

    Note: For most URL shorteners, especially at small to medium scale, the Random String + Collision Check method offers the best balance.

  3. How can we scale the system to handle High Traffic?

    • Sharding:

      • To handle high traffic and scale efficiently, we can use sharding to distribute data and load across multiple machines. This enables horizontal scaling, allowing us to add more nodes as traffic grows without major reconfiguration.
    • Load Balancing:

      • Use load balancers to distribute incoming requests evenly across services.
      • Prevents any one server from being overloaded.
    • CDN Edge Caching

      • Use a CDN (e.g., Cloudflare) to cache redirects at edge locations.
      • Reduces latency for global users.
      • Offloads requests before they even hit your backend.

Final Design

Final Design for URL Shortening Service


If you found this post helpful, feel free to:

  • 💬 Drop a comment — I’d love to hear your thoughts or answer your questions!

  • 🔁 Share it with others learning system design.

  • 📌 Follow me here on Dev.to for more deep dives like this!

Thanks for reading! :)

Top comments (0)