Back to blog

Build a URL Shortener: Series Overview & Architecture

typescriptnodejspostgresqlredisfullstack
Build a URL Shortener: Series Overview & Architecture

Every developer has used a URL shortener — Bit.ly, TinyURL, short.io. You paste a long link, get a short one back, share it, and it just works. Simple, right?

Behind that simplicity is a surprisingly rich engineering problem. Short code generation, collision handling, redirect performance, click analytics, caching layers, rate limiting, user authentication — a URL shortener touches almost every backend concept you'll encounter in real-world applications.

That's what makes it the perfect project to build from scratch. In this 15-post series, we'll go from an empty directory to a production-deployed, full-stack URL shortener with an admin panel and SEO optimization, using Express + TypeScript, PostgreSQL + Prisma, Redis, and React.

Why Build a URL Shortener?

A URL shortener is deceptively simple on the surface but covers a wide range of real-world backend challenges:

API design — RESTful endpoints with proper validation and error handling
Database modeling — schema design, indexes, migrations with Prisma ORM
Algorithm design — Base62 encoding, collision detection, custom alias handling
Performance optimization — Redis caching for sub-millisecond redirects
Analytics — tracking clicks, geolocation, referrers, device info
Authentication — JWT-based auth with user-scoped URL management
Full-stack development — React frontend with charts, QR codes, and dashboards
Testing — unit, integration, and load testing strategies
DevOps — Docker, CI/CD pipelines, monitoring, and production deployment

Unlike toy projects, a URL shortener has real production concerns: What happens when two users generate the same short code? How do you handle millions of redirects per day without melting your database? How do you prevent abuse?


What We're Building

By the end of this series, you'll have a fully functional URL shortener with these features:

Core Features

  • Shorten URLs — paste a long URL, get a short link back
  • Custom aliases — choose your own short code (e.g., short.ly/my-resume)
  • Redirect engine — fast 301/302 redirects with caching
  • Click analytics — track total clicks, unique visitors, referrers, devices, and geographic data
  • Expiration — set TTL on short links (auto-expire after N days)

Advanced Features

  • User accounts — register, login, manage your URLs in a dashboard
  • Rate limiting — prevent abuse with Redis-based rate limiting
  • QR code generation — generate QR codes for any shortened URL
  • Bulk shortening — shorten multiple URLs in one API call
  • API keys — programmatic access for integrations

Admin & SEO Features

  • Admin panel — role-based access control, user management, URL moderation
  • Abuse detection — domain blocklists, automated flagging, community reporting
  • System analytics — dashboard metrics, click trends, top URLs, user growth
  • Audit logs — track every admin action with detailed change history
  • Link previews — OG meta tag scraping, social share images, bot-aware redirects

Tech Stack

Here's every technology we'll use and why:

LayerTechnologyWhy
RuntimeNode.js 20+Non-blocking I/O, perfect for high-throughput redirect handling
FrameworkExpress.jsMinimal, flexible, battle-tested HTTP framework
LanguageTypeScript 5Type safety, better DX, catch bugs at compile time
DatabasePostgreSQL 16ACID compliance, powerful indexing, JSON support for analytics
ORMPrismaType-safe queries, auto-generated client, easy migrations
CacheRedis 7Sub-millisecond lookups for hot URLs, rate limiting, session store
AuthJWT + bcryptStateless authentication, secure password hashing
FrontendReact 19 + ViteFast dev experience, component-based UI, chart libraries
TestingVitest + Supertest + k6Unit, integration, and load testing
DevOpsDocker + GitHub ActionsContainerization, CI/CD, reproducible deployments
MonitoringPrometheus + GrafanaMetrics collection and visualization

System Architecture

Here's a high-level view of the system we'll build:

Request Flow: Shortening a URL

Request Flow: Redirecting


Database Schema Preview

Here's a simplified version of the schema we'll design and iterate on throughout the series:

Key design decisions we'll explore:

  • Why UUID over auto-increment? — prevents enumeration attacks on short codes
  • Why click_count on URLs table? — denormalized counter avoids expensive COUNT queries
  • Why separate clicks table? — granular analytics without bloating the URLs table
  • Indexes — we'll add composite indexes on (short_code, is_active) for fast lookups

Complete Series Roadmap

Post #1: Series Overview & ArchitectureYou are here

  • Why build a URL shortener
  • Tech stack decisions and trade-offs
  • System architecture and data flow
  • Database schema preview

Phase 1: Project Setup & URL Shortening API

Post #2: Phase 1 — Project Setup & URL Shortening API (Express + TypeScript)

Topics:

  • Project scaffolding with Express + TypeScript
  • Folder structure for scalable APIs
  • First endpoint: POST /api/shorten
  • URL validation and sanitization
  • In-memory storage (before we add a database)
  • Error handling middleware
  • Environment configuration with dotenv

Learning Outcomes:
✅ Set up a TypeScript + Express project from scratch
✅ Build a working URL shortening API endpoint
✅ Implement proper request validation and error handling
✅ Structure an Express project for growth


Phase 2: Database Design & URL Storage

Post #3: Phase 2 — Database Design & URL Storage (PostgreSQL + Prisma)

Topics:

  • PostgreSQL setup with Docker
  • Prisma schema design and migrations
  • CRUD operations for URLs
  • Database indexing strategy
  • Replacing in-memory storage with PostgreSQL
  • Connection pooling configuration

Learning Outcomes:
✅ Design a normalized database schema for URL shortening
✅ Use Prisma ORM for type-safe database operations
✅ Write efficient migrations and manage schema changes
✅ Optimize queries with proper indexing


Phase 3: Short Code Generation

Post #4: Phase 3 — Short Code Generation (Base62, Collision Handling, Custom Aliases)

Topics:

  • Base62 encoding algorithm
  • Short code length vs collision probability
  • Collision detection and retry strategies
  • Counter-based vs random generation trade-offs
  • Custom alias validation and reservation
  • URL deduplication (same URL → same short code?)

Learning Outcomes:
✅ Implement Base62 encoding for compact short codes
✅ Handle collisions gracefully at scale
✅ Support custom aliases with proper validation
✅ Understand the math behind short code uniqueness


Phase 4: Redirect Engine & Click Analytics

Post #5: Phase 4 — Redirect Engine & Click Analytics

Topics:

  • 301 vs 302 redirects (SEO implications)
  • Efficient redirect lookup pipeline
  • Click event recording (non-blocking)
  • Parsing user-agent, referrer, and IP geolocation
  • Analytics aggregation queries
  • Handling expired and deactivated URLs

Learning Outcomes:
✅ Build a high-performance redirect engine
✅ Record click analytics without blocking redirects
✅ Parse and store device, referrer, and geo data
✅ Write aggregation queries for analytics dashboards


Phase 5: Caching with Redis

Post #6: Phase 5 — Caching with Redis (URL Lookups & Rate Limiting)

Topics:

  • Redis setup and connection management
  • Cache-aside pattern for URL lookups
  • Cache invalidation strategies
  • TTL-based expiration for short URLs
  • Rate limiting with sliding window algorithm
  • Redis as a session store

Learning Outcomes:
✅ Implement cache-aside pattern for sub-millisecond redirects
✅ Handle cache invalidation correctly
✅ Build rate limiting to prevent API abuse
✅ Understand Redis data structures for real-world use cases


Phase 6: User Authentication & URL Management

Post #7: Phase 6 — User Authentication & URL Management Dashboard

Topics:

  • JWT authentication (access + refresh tokens)
  • User registration and login endpoints
  • Password hashing with bcrypt
  • Middleware-based route protection
  • User-scoped URL management (CRUD)
  • API key generation for programmatic access

Learning Outcomes:
✅ Implement JWT-based authentication from scratch
✅ Secure API routes with authentication middleware
✅ Build user-scoped resource management
✅ Generate and validate API keys


Phase 7: Frontend with React

Post #8: Phase 7 — Frontend with React (URL Creation, Analytics Charts, QR Codes)

Topics:

  • React + Vite project setup
  • URL shortening form with validation
  • Dashboard with URL management (list, edit, delete)
  • Analytics charts with Recharts (clicks over time, top referrers, device breakdown)
  • QR code generation with qrcode.react
  • Responsive design with Tailwind CSS

Learning Outcomes:
✅ Build a full-featured frontend for the URL shortener
✅ Display analytics data with interactive charts
✅ Generate QR codes for shortened URLs
✅ Connect a React frontend to an Express API


Phase 8: Testing Strategy

Post #9: Phase 8 — Testing Strategy (Unit, Integration, Load Testing)

Topics:

  • Unit testing with Vitest (services, utilities)
  • Integration testing with Supertest (API endpoints)
  • Database testing with test containers
  • Mocking Redis and external services
  • Load testing with k6 (redirect throughput, concurrent shortening)
  • Test coverage and CI integration

Learning Outcomes:
✅ Write unit tests for business logic and utilities
✅ Build integration tests for API endpoints
✅ Load test the redirect engine under high concurrency
✅ Set up test automation in CI/CD


Phase 9: Deployment & Production

Post #10: Phase 9 — Deployment & Production (Docker, CI/CD, Monitoring)

Topics:

  • Multi-stage Docker builds for API and frontend
  • Docker Compose for the full stack (API + PostgreSQL + Redis)
  • GitHub Actions CI/CD pipeline
  • Health check endpoints
  • Prometheus metrics and Grafana dashboards
  • Logging with structured JSON logs
  • Production hardening (CORS, Helmet, compression)

Learning Outcomes:
✅ Containerize the full application with Docker
✅ Set up CI/CD with GitHub Actions
✅ Monitor application health with Prometheus and Grafana
✅ Deploy a production-ready application with confidence


Phase 10: Admin Panel — RBAC & User Management

Post #11: Phase 10 — Admin Panel — RBAC & User Management

Topics:

  • Role-based access control (USER, ADMIN, SUPER_ADMIN)
  • Admin middleware for protecting admin-only routes
  • User management API (list, search, view details)
  • Account suspension and reactivation
  • Admin promotion and demotion
  • Seeding the first admin user

Learning Outcomes:
✅ Implement role-based access control with Prisma enums
✅ Build composable middleware for role checking
✅ Create admin user management endpoints
✅ Handle account suspension across the auth flow


Phase 11: URL Moderation & Abuse Detection

Post #12: Phase 11 — URL Moderation, Bulk Operations & Abuse Detection

Topics:

  • URL moderation workflow (active → flagged → disabled)
  • Admin URL listing with filters and search
  • Bulk operations (disable, delete, flag multiple URLs)
  • Domain blocklist management
  • Automated abuse detection (rate-based, pattern matching)
  • Community URL reporting system

Learning Outcomes:
✅ Build a URL moderation system with status workflows
✅ Implement bulk operations with transaction safety
✅ Create a domain blocklist to prevent malicious URLs
✅ Add automated abuse detection and community reporting


Phase 12: System Analytics & Audit Logs

Post #13: Phase 12 — System Analytics Dashboard & Audit Logs

Topics:

  • System dashboard API with key metrics
  • Time-series analytics (clicks, URL creation, user growth)
  • Top performers (most clicked URLs, most active users)
  • Geographic and device analytics
  • Admin audit log system
  • Audit log querying and filtering

Learning Outcomes:
✅ Build system-wide analytics with efficient aggregation queries
✅ Create time-series data endpoints for dashboard charts
✅ Implement a comprehensive audit log system
✅ Cache expensive analytics queries with Redis


Phase 13: React Admin Dashboard UI

Post #14: Phase 13 — React Admin Dashboard UI

Topics:

  • Admin layout with sidebar navigation
  • Dashboard overview with metric cards and trend indicators
  • Analytics page with Recharts charts
  • User management table with search and actions
  • URL moderation queue with bulk selection
  • Audit log viewer with expandable details

Learning Outcomes:
✅ Build a complete admin dashboard with React and Tailwind CSS
✅ Display analytics with interactive Recharts visualizations
✅ Create data tables with search, filters, and pagination
✅ Implement role-based route protection in React


Post #15: Phase 14 — SEO & Link Previews (OG Tags, Meta Scraping & Social Share Images)

Topics:

  • OG meta tag scraping from destination URLs
  • Link preview metadata storage and caching
  • Bot-aware redirect handling (crawlers vs humans)
  • Dynamic OG image generation with Satori
  • Preview page for short URLs
  • Social platform compatibility (Facebook, Twitter, Slack, LinkedIn, Discord)

Learning Outcomes:
✅ Scrape and cache OG metadata from destination URLs
✅ Serve rich link previews to social media bots
✅ Generate dynamic OG images for short links
✅ Handle bot detection and SSRF prevention


Architecture Decisions Explained

Before we start coding, let's understand a few key decisions:

Why Express over Fastify or Hono?

Express is the most widely used Node.js framework. It has the largest ecosystem, the most tutorials, and is still the default choice for most teams. While Fastify is faster and Hono is lighter, Express's middleware ecosystem and community support make it the best choice for learning. Everything you learn with Express transfers directly to other frameworks.

Why PostgreSQL over MongoDB?

URL shortening is inherently relational — URLs belong to users, clicks belong to URLs. PostgreSQL gives us:

  • ACID transactions for reliable short code generation
  • Unique constraints for collision prevention
  • Powerful indexing for fast lookups
  • JSON columns for flexible metadata storage
  • Window functions for analytics aggregation

Why Redis for Caching?

The redirect path is the hottest path in a URL shortener. A popular short link might get millions of hits. Redis gives us:

  • Sub-millisecond reads — 100x faster than a database query
  • Built-in TTL — automatic cache expiration
  • Atomic operations — perfect for rate limiting counters
  • Pub/Sub — cache invalidation across multiple instances

Why Prisma over raw SQL or Knex?

Prisma provides:

  • Type-safe queries — TypeScript types auto-generated from your schema
  • Declarative migrations — schema changes tracked in version control
  • Query engine — handles connection pooling and query optimization
  • Studio — visual database browser for development

Learning Paths

Choose the path that matches your goals:

Path 1: Backend Developer (Posts 1–6)

Time: 2–3 weeks, 1–2 hours daily
Focus: API design, database modeling, caching, performance

Skip the frontend (Post 8) and use curl or Postman to test your API. This path covers the core backend engineering concepts.

Path 2: Full-Stack Developer (All 15 Posts)

Time: 6–7 weeks, 1–2 hours daily
Focus: End-to-end application development

Follow every post in order. You'll build the complete application from API to frontend to deployment, then add admin features and SEO.

Path 3: DevOps Focus (Posts 1–2, 6, 9–10)

Time: 1–2 weeks, 1–2 hours daily
Focus: Containerization, testing, CI/CD, monitoring

Get the basic API running, then jump to Redis, testing, and deployment. This path focuses on infrastructure and operations.

Path 4: Admin & Security Focus (Posts 1–7, 11–13)

Time: 3–4 weeks, 1–2 hours daily
Focus: RBAC, moderation, abuse prevention, audit logging

Build the core API with auth, then dive into admin panel features. This path covers enterprise-grade access control and content moderation.


Prerequisites

Before starting this series, you should be comfortable with:

  • JavaScript/TypeScript — variables, functions, async/await, Promises
  • Node.js basics — npm, modules, basic HTTP concepts
  • SQL fundamentals — SELECT, INSERT, JOIN, indexes
  • Command line — navigating directories, running scripts
  • Git — commits, branches, basic workflow
  • Docker basics — running containers (we'll cover Docker Compose in detail)

New to TypeScript? Check out the TypeScript Full-Stack Roadmap first.

New to React? The frontend post (Post 8) assumes React knowledge. See the React Fundamentals post.


URL Shortener vs Other Projects

Why is a URL shortener better than a todo app or a blog for learning?

AspectTodo AppBlogURL Shortener
CRUD complexityBasicMediumHigh (URLs + Users + Clicks)
Performance needsLowLowHigh (redirect latency matters)
CachingUnnecessaryOptionalEssential
AnalyticsNonePage viewsRich click analytics
Auth complexitySimpleMediumAPI keys + JWT + rate limiting
System designTrivialSimpleReal interview-level design
DevOpsBasicBasicFull stack (Redis, Postgres, Docker)

A URL shortener is complex enough to teach real engineering skills but focused enough to finish in a few weeks. It's also a classic system design interview question — building one gives you deep understanding of the trade-offs.


What's Next?

In Post #2, we'll set up our Express + TypeScript project from scratch, build the first POST /api/shorten endpoint, and get our URL shortener returning real short codes. No database yet — we'll use in-memory storage to focus purely on API design and validation.

Let's build something real.

Series: Build a URL Shortener
Next: Phase 1: Project Setup & URL Shortening API

📬 Subscribe to Newsletter

Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.

We respect your privacy. Unsubscribe at any time.

💬 Comments

Sign in to leave a comment

We'll never post without your permission.