URL shortener system design

Designing a URL Shortener Like Bitly: Step-by-Step Guide

We’ve all seen really long, ugly links. Imagine trying to share this in a tweet or a message:

https://www.thebasictechinfo.com/blogs/backend/system-design/how-to-handle-millions-of-users?ref=linkedin&utm=seo_campaign

Now compare it with this:

https://bit.ly/sysdesign2025

That looks cleaner, shorter, and easier to share. This is why URL shorteners like Bitly or TinyURL are so popular.

But have you ever thought about how they work internally? Or better yet, can you build one yourself? The good news: yes, and you’ll learn a lot along the way.

In this article, we’ll break down the system design of a URL shortener, see how it works step by step, and even write some code that can run locally.

Why Build a URL Shortener?

For developers, building a URL shortener is more than just a fun project:

  • It’s a real-world problem: You’ll deal with databases, caching, and APIs.
  • It’s a common interview question: Many system design interviews ask you to design Bitly or TinyURL.
  • It’s a scalable problem: At first, it looks simple. But when you think about millions of users, you’ll face real challenges.
  • It’s a portfolio project: Great to showcase if you want to prove your backend skills.

How Does a URL Shortener Work?

Let’s keep it simple. Here’s the flow:

  1. User enters a long URL (like https://www.thebasictechinfo.com/...).
  2. Service validates the link (is it a real URL, is it safe, is it allowed?).
  3. A short code is generated (like aB12xYz).
  4. Mapping is saved in a database: short code → original URL.
  5. When someone clicks the short link, the service looks it up and redirects the browser.

Sounds simple? It is. But scaling it for millions of requests brings interesting challenges.

Key Features to Add

A real-world shortener like Bitly doesn’t stop at just redirects. It also includes:

  • Custom aliases: Let users choose bit.ly/myblog2025 instead of random code.
  • Expiry dates: Links can auto-expire after a certain time.
  • Analytics: Track how many clicks a link got, from which region, on what device.
  • Rate limiting: Prevent abuse by limiting requests per IP.
  • Caching: Speed up hot link lookups with Redis or Memcached.
  • Security checks: Block malicious domains and prevent open redirects.

System Design of a URL Shortener

Components

  • API Server: Handles requests, generates codes, redirects.
  • Database: Stores short code → original URL mapping. (PostgreSQL, MySQL, or even NoSQL like DynamoDB).
  • Cache: Redis for fast lookups of popular links.
  • Load Balancer: To scale horizontally with multiple API servers.
  • Background Worker: For analytics tracking (so redirects are fast).

Data Flow Example

  1. You hit POST /shorten with a long URL.
  2. API checks if the domain is allowed, generates a short code, and stores it.
  3. API returns the short link (https://myshort.com/abc123).
  4. When someone clicks the link, the service looks it up (Redis first, DB fallback) and redirects.
  5. Analytics data (clicks, referrers) are updated in the background.

Code Example: Generating a Short Code

Here’s a simple Node.js example using nanoid to generate a unique short code:

import { customAlphabet } from 'nanoid';

// base62 alphabet: numbers + letters
const alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const generateCode = customAlphabet(alphabet, 8);

function shortenUrl(longUrl) {
  const code = generateCode();
  return { code, shortUrl: http://localhost:3000/${code}, longUrl };
}

// Example
console.log(shortenUrl("https://www.thebasictechinfo.com/article/system-design"));

Output:

{
  code: "aZ81kP3Q",
  shortUrl: "http://localhost:3000/aZ81kP3Q",
  longUrl: "https://www.thebasictechinfo.com/article/system-design"
}

This is just the starting point. In production, you’d:

  • Save the mapping in a database.
  • Add an expiry date.
  • Handle collisions if the code already exists.

Scaling Challenges

When building something like Bitly, you’ll hit real-world issues:

  • Collisions: Two users generating the same short code. Fix: Retry with a new code or use a bigger code space.
  • Database size: Millions of URLs need indexing. Fix: Partition/shard data.
  • Hot links: Some links go viral. Fix: Use Redis cache to avoid hammering the DB.
  • Abuse prevention: Spammers may shorten phishing links. Fix: Maintain allow/deny lists.
  • Analytics storage: Click tracking can get huge. Fix: Store only aggregated data or move to a data warehouse.

Developer Growth: What You’ll Learn

By building a shortener, you’ll touch on:

  • Database indexing and schema design.
  • Caching strategies.
  • API design and rate limiting.
  • Security best practices.
  • System scaling.

These are exactly the skills you’ll be tested on in backend/system design interviews.

Interview Prep Questions

Q1. How do you generate unique short codes?
Use a base62 alphabet with 7–9 characters. Retry if collision happens.

Q2. How do you handle billions of URLs?
Partition/shard by code prefix, and add caching.

Q3. How do you prevent abuse?
Domain allow/deny lists, IP rate limiting, and link expiry.

Q4. How do you scale click tracking?
Use async workers or streaming pipelines (Kafka, Kinesis) to handle logs separately.

Q5. What’s the average length of a short code?
8 characters in base62 gives ~218 trillion possible codes, which is plenty.

FAQs

Can I build this as a project?
Yes! Start with Node.js, PostgreSQL, and Redis. You’ll learn a lot.

Do I need caching?
Not for small projects. But if you expect traffic, caching saves your DB from overload.

Can I extend it?
Yes. Add analytics dashboards, QR code generation, or custom domains.

A URL shortener looks simple, but when you think about scale and security, it teaches you a ton about backend systems. Whether you’re preparing for interviews or just building a cool project, this is one of the most rewarding systems you can implement.