Designing a Scalable URL Shortener: Snowflake IDs, Base62 Encoding, and Microservices
Designing a Scalable URL Shortener: Snowflake IDs, Base62 Encoding, and Microservices

URL shorteners like Bit.ly or TinyURL are deceptively simple: take a long URL, generate a short one, and redirect. But when you want to scale to billions of URLs with low latency, careful system design is crucial. In this article, we’ll break down a full architecture for a production-ready URL shortener.

1. Requirements

Before we design, let’s define the requirements:

Functional Requirements:

  1. Create short URLs from long URLs.
  2. Redirect short URLs to the original URLs.
  3. Support custom / vanity URLs.
  4. Track analytics (clicks, unique users).

Non-Functional Requirements:

  1. High availability (99.9% uptime).
  2. Low latency for redirects (<50ms median).
  3. Scalability to billions of URLs.
  4. Security (rate limiting, malware detection).

2. Generating Unique Short IDs

We need a unique identifier for each URL. There are multiple approaches:

  • Auto-incrementing IDs: easy but predictable.
  • Random IDs: harder to guess.
  • Snowflake IDs: distributed, sortable, globally unique.

Snowflake IDs

Snowflake is a 64-bit unique ID generator originally used by Twitter.

BitsMeaning
1Sign bit (unused)
41Timestamp in milliseconds since custom epoch
10Machine ID (datacenter + worker)
12Sequence number per millisecond

Example Calculation:

Timestamp = 100,000 ms since epoch
Machine ID = 17
Sequence = 25

ID = (100000 << 22) | (17 << 12) | 25
   = 419,430,469,657

3. Base62 Encoding

The Snowflake ID is a large integer. To make it URL-friendly, we encode it in Base62 (0-9, A-Z, a-z):

Step-by-Step:

  1. Divide the integer by 62, store remainder as character.
  2. Repeat until quotient = 0.
  3. Reverse remainders → short string.

Example:

ID = 419,430,469,657 → Base62 = "7LLBP0o"

This short string becomes the short URL:

https://short.ly/7LLBP0o

4. High-Level Architecture

Here’s the architecture of our system:

          ┌───────────────┐
          │     User      │
          │(Browser/App)  │
          └───────┬───────┘
                  │ POST /shorten or GET /s/:id
                  ▼
          ┌───────────────┐
          │  API Gateway  │
          │  (Auth, Rate  │
          │  Limiting, LB)│
          └───────┬───────┘
                  │
      ┌───────────┴───────────┐
      ▼                       ▼
┌───────────────┐        ┌───────────────┐
│ Shortlink     │        │ Analytics      │
│ Service       │        │ Service        │
│ - Validates   │        │ - Consumes     │
│ - Generates   │        │   click events │
│   Snowflake ID│        │ - Aggregates   │
│ - Base62 enc  │        │ - Stores in OLAP│
│ - Stores DB   │        │                │
│ - Updates Redis│       │                │
└─────┬─────────┘        └───────────────┘
      │
      ▼
┌───────────────┐
│  Redis Cache  │  ← Hot cache for redirects
└─────┬─────────┘
      ▼
┌───────────────┐
│  Primary DB   │  ← Source-of-truth
│ shortlinks    │
│ schema:       │
│ - short_id    │
│ - original_url│
│ - owner_id    │
│ - created_at  │
└───────────────┘

5. Detailed Flow

Creating a Short URL

  1. User sends POST /shorten with URL (and optional custom alias).
  2. API Gateway authenticates, enforces rate limits, forwards request to Shortlink Service.
  3. Service generates a Snowflake ID, converts it to Base62, and stores it in DB and Redis cache.
  4. Returns https://short.ly/{short_id}.

Redirecting a Short URL

  1. User clicks GET /s/{short_id}.
  2. CDN / Redis cache checked for mapping.
  3. Cache hit → HTTP 301 redirect.
  4. Cache miss → query DB → update cache → redirect.
  5. Push click event to Kafka for analytics.

6. Handling Custom / Vanity URLs

  • Validate input (allowed characters, reserved words).
  • Ensure uniqueness using DB constraint.
  • For collisions, return error or ask user to choose another alias.

7. Scaling Considerations

  • Microservices: Shortlink Service, Analytics Service, User Service, etc.
  • DB sharding: shard by short_id hash to scale billions of URLs.
  • Caching: Redis + CDN to reduce latency.
  • Analytics: Kafka for asynchronous event processing.
  • Snowflake IDs: distributed unique ID generation across multiple servers.

8. JavaScript Example

// Base62 encoding
const BASE62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
function encodeBase62(num) {
  if (num === 0) return '0';
  let str = '';
  while (num > 0) {
    str = BASE62[num % 62] + str;
    num = Math.floor(num / 62);
  }
  return str;
}

// Simplified Snowflake ID generator
class Snowflake {
  constructor(machineId = 1) {
    this.machineId = machineId & 0x3FF;
    this.sequence = 0;
    this.lastTimestamp = -1;
    this.epoch = 1700000000000;
  }
  currentTime() { return Date.now() - this.epoch; }
  nextId() {
    let timestamp = this.currentTime();
    if (timestamp === this.lastTimestamp) this.sequence = (this.sequence + 1) & 0xFFF;
    else this.sequence = 0;
    this.lastTimestamp = timestamp;
    return (BigInt(timestamp) << 22n) | (BigInt(this.machineId) << 12n) | BigInt(this.sequence);
  }
}

// Usage
const snowflake = new Snowflake(1);
const id = snowflake.nextId();
const shortId = encodeBase62(Number(id % BigInt(Number.MAX_SAFE_INTEGER)));
console.log('Short ID:', shortId);

9. Key Takeaways

  1. Snowflake IDs + Base62 → scalable, unique, URL-friendly IDs.
  2. Cache first (Redis/CDN) → low-latency redirects.
  3. Microservices + Sharding → handle billions of URLs.
  4. Asynchronous analytics → decoupled pipeline for clicks.
  5. Custom aliases → validated and constrained in DB.

This architecture can support high availability, billions of URLs, and low-latency redirects, making it suitable for production systems like Bit.ly.

List of Some important Leet code Questions:

SystemDesign#BackendEngineering#SoftwareArchitecture#Microservices#Redis#Kafka#NodeJS#Scalability#BackendDeveloper#FullStackEngineer#CloudArchitecture#WebPerformance#InterviewPrep#DistributedSystems#EngineeringDesign

Written by

’m Nilesh, a Software Development Engineer with 2+ years of experience, specializing in Go, JavaScript, Python, Docker, Kubernetes, Git, Jenkins, microservices, and system design (LLD/HLD), backed by a strong foundation in data structures and algorithms. Alongside my engineering journey, I bring 4+ years of hands-on experience in SEO, where I’ve worked extensively on content strategy, keyword research, technical SEO, and organic growth, helping products and businesses scale efficiently by aligning solid technology with search-driven performance.