A full-stack-ready, production-grade URL shortener built with NestJS, Prisma, Passport.js, and Redis.
This project was created to learn, experiment, and try new technologies including:
- Third-party authentication (OAuth) with Google and GitHub using Passport.js
- Docker and Docker Compose for containerization and orchestration
- Caching with Redis (via Docker Compose)
- Advanced NestJS features: custom guards, decorators, DTO validation, Prisma exception handling, and more
- Features
- Architecture Overview
- How It Works (Diagram)
- Getting Started
- Environment Variables
- API Endpoints
- Authentication Flow
- Caching & Redis
- Docker & Docker Compose
- Testing
- Project Structure
- Tech Stack
- License
- Shorten URLs: Authenticated users can create, update, delete, and list their own short URLs.
- Third-Party Authentication: Login with Google or GitHub using OAuth 2.0 (Passport.js).
- Session Management: Secure sessions with
express-session
and Passport. - Caching: Redis-backed cache for fast URL lookups and reduced DB load.
- Rate Limiting: Multiple throttling strategies using NestJS Throttler.
- Validation: DTO validation with Joi and custom NestJS pipes.
- Soft Delete: URLs are soft-deleted (marked with
deletedAt
), not removed from DB. - Statistics: Track and retrieve access counts for each short URL.
- Prisma ORM: Type-safe DB access, migrations, and seeding.
- Error Handling: Custom Prisma exception filter for user-friendly errors.
- Dockerized: Production-ready Dockerfile and Compose setup (app + Redis).
- Environment Config: All secrets and configs via
.env
file. - Extensible: Modular NestJS codebase, ready for new features.
- NestJS: Main backend framework (controllers, modules, DI, etc.)
- Prisma: ORM for PostgreSQL (models:
Users
,ShortURLs
) - Supabase: Hosting the PostgreSQL database
- Passport.js: Handles OAuth with Google and GitHub
- Redis: Used as a cache for short URL lookups
- Docker Compose: Orchestrates the app and Redis containers
- Docker & Docker Compose
- Node.js (for local dev)
- PostgreSQL database (or use Supabase)
git clone https://github.com/your-username/short-url.git
cd short-url
Copy .env.example
to .env
and fill in your secrets:
cp .env.example .env
# Edit .env with your DB, OAuth, and session secrets
docker build --build-arg DATABASE_URL=db-url \
--build-arg DIRECT_URL=db-direct-url \
-t opt-nest-short-url .
docker compose up
- App runs on http://localhost:3000
- Redis runs on port 6379
Install dependencies and run in watch mode:
npm install
npm run start:dev
See .env
:
DATABASE_URL
- PostgreSQL connection stringDIRECT_URL
- Direct DB connection (for migrations)GOOGLE_CLIENT_ID
/GOOGLE_CLIENT_SECRET
- Google OAuthGITHUB_CLIENT_ID
/GITHUB_CLIENT_SECRET
- GitHub OAuthSESSION_SECRET
- Secret for session encryptionFRONTEND_URL
- Allowed CORS origin and redirect targetREDIS_URL
- Redis connection string (redis://redis_cache:6379
for Docker Compose)
GET /auth/google/login
- Start Google OAuthGET /auth/google/redirect
- Google OAuth callbackGET /auth/github/login
- Start GitHub OAuthGET /auth/github/redirect
- GitHub OAuth callbackGET /auth/logout
- Logout and destroy sessionGET /auth/status
- Get current user info (if authenticated)
POST /shorten
- Create a new short URL (body:{ url: string }
)GET /shorten/all
- List all user's short URLsGET /shorten/:short
- Get info for a specific short URLPUT /shorten/:short
- Update a short URLDELETE /shorten/:short
- Soft-delete a short URLGET /shorten/:short/stats
- Get stats for a short URL
GET /:short
- Redirect to the original URL
- Uses Passport.js with Google and GitHub strategies
- On successful OAuth, user is created or updated in DB
- Session is stored using
express-session
(cookie-based) - Custom session serializer for minimal session data
- Logout endpoint destroys session and clears cookie
- Uses
@nestjs/cache-manager
with@keyv/redis
for Redis integration - Short URL lookups are cached for 1 hour
- Cache is checked before DB on each redirect
- Redis runs as a service in Docker Compose
- Dockerfile: Multi-stage build (builder + production)
- compose.yml: Runs app and Redis, mounts Redis data volume
- .dockerignore: Ignores
node_modules
,dist
,.env
,.git
- Environment: All secrets/configs injected at runtime
- Currently no tests are implemented.
src/
app.controller.ts # Handles redirects
app.module.ts # Root module
app.service.ts # Redirect logic, caching
main.ts # App bootstrap, session, passport
auth/ # Auth module (OAuth, guards, session)
auth.controller.ts
auth.service.ts
utils/
google.guard.ts
github.guard.ts
authenticated.guard.ts
session-serializer.ts
user.decorator.ts
google.strategy.ts
github.strategy.ts
shorten/ # Shorten module (CRUD for short URLs)
shorten.controller.ts
shorten.service.ts
dto/
prisma/ # Prisma service, exception filter
prisma.service.ts
prisma-client-exception/
common/pipes/ # Joi validation pipe
utils/ # Nanoid generator
prisma/
schema.prisma # DB schema
seed.ts # Seed script
Dockerfile
compose.yml
.env
- NestJS (TypeScript)
- Prisma (ORM)
- Supabase (PostgreSQL)
- Passport.js (OAuth)
- Redis (Cache)
- Docker / Docker Compose
- Joi (Validation)
- Jest (Testing)
This project is licensed under the MIT License.