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:
| Layer | Technology | Why |
|---|---|---|
| Runtime | Node.js 20+ | Non-blocking I/O, perfect for high-throughput redirect handling |
| Framework | Express.js | Minimal, flexible, battle-tested HTTP framework |
| Language | TypeScript 5 | Type safety, better DX, catch bugs at compile time |
| Database | PostgreSQL 16 | ACID compliance, powerful indexing, JSON support for analytics |
| ORM | Prisma | Type-safe queries, auto-generated client, easy migrations |
| Cache | Redis 7 | Sub-millisecond lookups for hot URLs, rate limiting, session store |
| Auth | JWT + bcrypt | Stateless authentication, secure password hashing |
| Frontend | React 19 + Vite | Fast dev experience, component-based UI, chart libraries |
| Testing | Vitest + Supertest + k6 | Unit, integration, and load testing |
| DevOps | Docker + GitHub Actions | Containerization, CI/CD, reproducible deployments |
| Monitoring | Prometheus + Grafana | Metrics 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_counton URLs table? — denormalized counter avoids expensive COUNT queries - Why separate
clickstable? — 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 & Architecture ✅ You 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
Phase 14: SEO & Link Previews
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?
| Aspect | Todo App | Blog | URL Shortener |
|---|---|---|---|
| CRUD complexity | Basic | Medium | High (URLs + Users + Clicks) |
| Performance needs | Low | Low | High (redirect latency matters) |
| Caching | Unnecessary | Optional | Essential |
| Analytics | None | Page views | Rich click analytics |
| Auth complexity | Simple | Medium | API keys + JWT + rate limiting |
| System design | Trivial | Simple | Real interview-level design |
| DevOps | Basic | Basic | Full 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.