All Articles
How I Built My URL Shortener in Go
Backend Engineering

How I Built My URL Shortener in Go

A deep dive into building a high-performance URL shortener with Go, PostgreSQL, and Redis — focusing on clean architecture and sub-5ms response times.

#Go#PostgreSQL#Redis#System Design
D
Dipankar Ghosh
8 min read

Here are my insights I came up with while making my URL shortener

Introduction

URL shorteners look deceptively simple: store a long URL, generate a short code, and redirect users when the short link is visited.

In reality, a production-ready URL shortener must solve several engineering problems:

  • Fast redirect performance
  • High read throughput
  • Abuse prevention
  • Analytics collection
  • Authentication and authorization
  • Cache consistency

To explore these challenges, I built a URL shortener using Go, Gin, PostgreSQL, and Redis, with JWT-based authentication and analytics tracking.

Tech Stack

Backend

  • Go
  • Gin
  • PostgreSQL
  • Redis
  • JWT Authentication
  • Docker

Infrastructure

  • GitHub Actions (CI)
  • Docker Compose
  • Redis Cache
  • PostgreSQL Database

System Architecture

The application is organized into three primary layers:

Client
   │
   ▼
Gin API Server
   │
   ├── Redis Cache
   │
   └── PostgreSQL

API Layer

The API layer handles:

  • URL creation
  • URL redirects
  • Authentication
  • Analytics retrieval
  • Request validation
  • Rate limiting

Cache Layer

Redis serves two purposes:

  1. URL lookup caching
  2. Rate limiting

The cache significantly reduces database load for frequently accessed links by serving redirect requests directly from memory. Cache-aside architectures are commonly used in URL shorteners because they keep the database as the source of truth while reducing latency on hot paths.

Database Layer

PostgreSQL acts as the source of truth and stores:

  • Users
  • URLs
  • Click events
  • Analytics data

Data Model

The current schema revolves around three main entities:

Users

users
├── id
├── email
├── password_hash
└── created_at

URLs

urls
├── id
├── user_id
├── short_url
├── long_url
├── expiry
├── clicks
└── created_at

Click Events

click_events
├── id
├── url_id
├── ip_address
├── browser
├── device
├── country
├── referer
└── created_at

This relationship allows every URL to be associated with a specific user while maintaining detailed click analytics.

Authentication & Authorization

The application uses JWT-based authentication.

Registration Flow

User Registers
      │
      ▼
Password Hashed (bcrypt)
      │
      ▼
User Stored in PostgreSQL
      │
      ▼
JWT Generated

Login Flow

Email + Password
      │
      ▼
User Lookup
      │
      ▼
Password Verification
      │
      ▼
JWT Issued

The JWT contains the authenticated user's ID, which is injected into the request context by middleware.

JWT
  │
  ▼
Auth Middleware
  │
  ▼
userID in Context

This user ID is then used to authorize access to resources such as analytics dashboards.

URL Creation

Authenticated users can create short URLs with:

  • Auto-generated short codes
  • Custom aliases
  • Expiration support
  • Validation checks

Before a URL is stored:

  1. The request is validated.
  2. Custom aliases are checked for uniqueness.
  3. Ownership is attached using the authenticated user ID.
  4. The record is persisted in PostgreSQL.

Redirect Flow

The redirect endpoint is the most performance-sensitive part of the system.

Current redirect workflow:

Request
   │
   ▼
Redis Lookup
   │
   ├── Cache Hit
   │       │
   │       ▼
   │   Redirect
   │
   └── Cache Miss
           │
           ▼
      PostgreSQL
           │
           ▼
      Update Cache
           │
           ▼
        Redirect

This follows the Cache-Aside pattern, where the application first checks Redis and falls back to PostgreSQL only when necessary. This approach is widely used to reduce database load and improve response latency.

Click Tracking

Every redirect generates analytics data.

The application records:

  • Visitor IP address
  • User agent
  • Browser
  • Device type
  • Referrer
  • Timestamp

Each redirect performs:

Redirect Request
      │
      ▼
Increment Click Counter
      │
      ▼
Create Click Event
      │
      ▼
Redirect User

This enables analytics without requiring external tracking services.

Analytics Dashboard Backend

The analytics system currently supports:

Overview Metrics

  • Total clicks
  • Clicks today
  • Clicks this week
  • Clicks this month

Daily Activity

Daily click aggregation for chart visualizations.

Recent Visits

Recent visitor activity including:

  • Browser
  • Device
  • Referrer
  • Timestamp

Access Control

Analytics are protected through ownership checks.

Request Analytics
        │
        ▼
Extract userID from JWT
        │
        ▼
Fetch URL
        │
        ▼
Verify Ownership
        │
        ▼
Return Analytics

Users can only access analytics for URLs they own.

Rate Limiting

To prevent abuse, Redis-backed rate limiting is applied to API endpoints.

Different endpoints have different limits depending on their usage pattern.

Examples include:

  • URL creation
  • Redirect endpoints
  • Analytics endpoints

This helps protect infrastructure while maintaining responsiveness.

What I Learned

Building this project highlighted several real-world backend engineering concepts:

  • Cache-aside architecture
  • Authentication vs authorization
  • Redis caching strategies
  • Analytics event collection
  • Database relationship design
  • API rate limiting
  • Production-oriented Go application structure

More importantly, it demonstrated how quickly a seemingly simple service evolves into a system that requires thoughtful architecture and performance considerations.

What's Next

Planned improvements include:

  • Analytics dashboard frontend in Next.js
  • Browser and device distribution analytics
  • Azure deployment
  • Refresh token authentication
  • Advanced dashboard metrics
  • QR code generation
  • Custom domains
  • Observability and monitoring

The goal is to continue evolving the project into a production-grade URL shortening platform while exploring backend system design concepts in practice.

Tags
#Go#PostgreSQL#Redis#System Design