URL Shortener with Real-Time Analytics

A production-grade Bitly-style URL shortener with real-time analytics. Users paste a long URL and get a short one. A dashboard shows click counts, geo data, referrer sources, and device breakdown — all updated in real time via async click tracking.

Estimated monthly cost: ~$33–58/mo | Runtime: Node.js 20 | Orchestration: Kubernetes on AWS EKS | Region: us-east-1


How it works

Shorten flow — The Next.js frontend sends the long URL to a Fastify API. The API validates the input, generates a nanoid slug, writes to Redis (24hr TTL cache) and PostgreSQL, then returns the short link to the user.

Redirect + tracking flow — When a visitor clicks the short link, the API checks Redis first (cache hit ~1ms), falls back to PostgreSQL on a miss, then issues a 302 redirect. A BullMQ job is immediately enqueued so a background worker can parse geo data, detect device type, and record the click — all without delaying the redirect response.


Services used

Compute & orchestration

ServiceRole
AWS EKSManaged Kubernetes control plane — hosts all three app services
EKS node group (t3.small spot)Single node group, 1–3 nodes, spot pricing for cost savings
Frontend deploymentNext.js 14 served via Nginx, HPA enabled
API deploymentFastify REST API, HPA min 1 max 5 at 70% CPU
Worker deploymentBullMQ consumer, processes click jobs async

Networking & ingress

ServiceRole
AWS ALBInternet-facing load balancer, terminates HTTPS
AWS Load Balancer ControllerProvisions ALB from Kubernetes Ingress resources
cert-manager + Let’s EncryptAutomatic TLS certificate provisioning and renewal
Route 53DNS — CNAME pointing domain to ALB hostname

Data & storage

ServiceRole
PostgreSQL (Bitnami Helm)Primary database — urls and clicks tables, 10Gi PVC
Redis (Bitnami Helm)URL cache (24hr TTL per slug) + BullMQ job queue
ECRThree repositories — api, worker, frontend — images tagged by Git SHA

Async processing

ServiceRole
BullMQJob queue backed by Redis — fires click tracking job on every redirect
Worker (Node.js)Consumes BullMQ jobs, parses geo from IP (geoip-lite), detects device type, writes to Postgres

Observability

ServiceRole
Prometheus + PushgatewayMetrics from all three services — redirect latency, click rate, error rate
GrafanaDashboards stored as JSON in repo, applied via Terraform Grafana provider
Fluent BitShips container logs to CloudWatch

CI/CD pipeline

ServiceRole
GitHub ActionsTwo workflows — deploy.yml (push to main) and pr-check.yml (PRs)
Docker build matrixBuilds api, worker, frontend images in parallel
ECR pushImages tagged with $GITHUB_SHA — every deploy is traceable to a commit
kubectl set imageRolling update — zero downtime deploy on every push to main

Key design decisions

302 redirects, not 301 — 302 (temporary) redirects are used so browsers don’t cache them permanently. Every click hits the API, ensuring accurate analytics. 301 redirects would bypass the server on repeat visits and break click counts.

Redis-first cache strategy — every redirect checks Redis before hitting Postgres. Cache hit latency is ~1ms vs ~10ms for a DB query. At 90%+ cache hit rate, the API stays fast under load with minimal database pressure.

Async click tracking with BullMQ — the redirect response is sent immediately. Click tracking (geo lookup, device parsing, DB write) happens in a background worker. This keeps P99 redirect latency under 50ms regardless of database load.

nanoid for slug generation — 6-character URL-safe slugs give ~68 billion combinations. Cryptographically random, no collision risk at portfolio scale.

HPA on the API — the API deployment scales automatically between 1 and 5 replicas at 70% CPU. Demonstrates Kubernetes-native scaling in the demo.

Dashboards as code — Grafana dashboards are stored as JSON in /grafana/dashboards/ and applied via the Terraform Grafana provider. No manual dashboard configuration — everything is reproducible from the repo.


Project structure

url-shortener/
├── .github/workflows/      # deploy.yml + pr-check.yml
├── frontend/               # Next.js 14 app + Dockerfile
├── api/                    # Fastify API + routes + services + Dockerfile
├── worker/                 # BullMQ worker + Dockerfile
├── k8s/base/               # Deployment, Service, HPA, Ingress manifests
├── k8s/overlays/           # dev + prod environment patches
├── docs/                   # architecture.md, data-model.md, api-spec.md, runbook.md
├── scripts/                # setup-eks.sh, setup-ecr.sh, local-seed.sh
└── docker-compose.yml      # full local dev environment