A production-inspired URL shortener built with Node.js, Express, MongoDB, Redis, and React, focused on security, performance, and fault-tolerant backend design.
Unlike typical URL shorteners, this system is designed to continue functioning even if Redis (cache layer) is unavailable, ensuring reliability under real-world failure conditions.
- Fault Tolerance First β System works even if Redis fails
- MongoDB as Source of Truth β No dependency on cache correctness
- Non-blocking Request Flow β Fast redirects, async updates
- Security + Performance Balance β Avoid over-engineering
Client
β
Express API (Render)
β
Redis (optional cache)
β
MongoDB (primary database)
- Shorten long URLs
- Optional custom alias (unique enforced)
- Expiry control (default: 5 days, max: 7 days)
- URL history with metadata
- Click tracking
- Disable & delete URLs
- Automatic expiry handling
- URL risk analysis (phishing & suspicious pattern detection)
- Google Safe Browsing integration
- VirusTotal scanning
- Cached scan results (avoid re-scanning safe URLs)
- IP-based rate limiting (Redis-backed, fault-tolerant)
- Admin-enforced blocking (disabled/deleted URLs)
- View security logs
- Detect high-risk URL attempts
- Disable or delete malicious URLs
- Manual moderation controls
1. User hits /:shortCode
2. Try Redis cache
β If hit β validate β redirect
3. Cache miss β query MongoDB
4. Validate (active / not expired / not deleted)
5. Redirect immediately
6. Cache result (non-blocking)
7. Increment clicks asynchronously
- System falls back to MongoDB
- No broken redirects
- Only performance degradation
- Rate limiter prevents abuse
- Cache reduces database load
- Returns static error page (410 Gone)
User Input URL
β
Validation (Zod)
β
Admin Flag Check
β
Risk Score Analysis
β
Recent Safe Scan? β Skip
β
Google Safe Browsing
β
VirusTotal Scan
β
Security Logs Stored
β
URL Created
- Safe URLs are not re-scanned within 2 weeks
- Security logs stored in
SecurityLogcollection - High-risk URLs blocked early
- Reduces API cost and improves performance
- URL caching β
url:{shortCode} - Rate limiting β
rl:{ip} - Minimal Redis operations per request
- Redis treated as non-critical dependency
- Node.js + Express
- MongoDB (Mongoose)
- Redis (Upstash)
- Zod (validation)
- Helmet, HPP
- React + Vite
- Redux Toolkit
- Tailwind CSS
- Indexed lookup on
shortCode - Lean queries (
.lean()) - Reduced Redis calls per request
- Async DB updates for clicks
- Cache TTL optimization (24h)
| Job | Purpose |
|---|---|
| Expiry Job | Marks expired URLs |
| (Optional) Redis Sync | Can sync stats if needed |
URL-SHORTENER/
β
βββ url-shortener-backend/ # Express.js Server Logic
β βββ config/ # Database & Service configs (e.g., redis)
β βββ controllers/ # API Logic (Auth, URL, Admin, Security)
β βββ crons/ # Scheduled Background Tasks
β βββ jobs/ # Worker processes or specific task logic
β βββ middleware/ # Security, Auth, and Rate Limiting
β βββ models/ # Mongoose Schemas (User, URL, Logs)
β βββ public/ # Static Assets & Error Pages
β βββ routes/ # API Route Definitions
β βββ security/ # Advanced Security Guards & Analyzers
β βββ utils/ # Shared Helpers (ApiError, tokens, etc.)
β βββ app.js # App initialization
β βββ index.js # Server Entry Point
β βββ tredish.js # Redis client initialization
β
βββ url-shortener-frontend/ # React + Vite Frontend
β βββ public/ # Assets (logo.svg, Vivek.png)
β βββ src/ # Application Source Code
β β βββ App/ # Core App wrappers
β β βββ components/ # Global reusable UI (Navbar, Inputs)
β β βββ Features/ # Business logic modules
β β βββ Pages/ # View Components (Dashboard, Profile)
β β βββ utils/ # API clients and Formatters
β β βββ App.jsx # Root Component
β β βββ index.css # Global Styles
β β βββ main.jsx # React Entry Point
β βββ index.html # Main HTML Shell
β βββ vercel.json # Deployment configuration
β βββ vite.config.js # Vite build settings
β
βββ .gitignore # Root git ignore
βββ README.md # Main Project Documentation
- Custom alias must be unique
- Expiry limited to 7 days
- Safe handling of empty fields
- Strict schema validation using Zod
PORT=5000
MONGO_URL=your_mongodb_uri
REDIS_URL=your_upstash_url
REDIS_TOKEN=your_upstash_token
JWT_ACCESS_SECRET=your_secret
JWT_REFRESH_SECRET=your_secret
VIRUS_TOTAL_API_KEY=your_key
GOOGLE_SAFE_BROWSING_KEY=your_keyVITE_B_LOCATION=http://localhost:5000# Backend
npm install
node index.js
# Frontend
npm install
npm run devThis project demonstrates:
- Fault-tolerant backend design
- Real-world caching strategy (Redis as optional)
- Security-first URL handling
- Clean architecture & separation of concerns
- Practical trade-offs instead of overengineering
Vivek Focused on building reliable, scalable, real-world systems