A modern, self-hosted link shortener built with Next.js, featuring Google OAuth authentication, PostgreSQL database, and comprehensive analytics.
- 🔗 URL Shortening: Create short links with custom or auto-generated codes
- 🔐 Single-User Auth: Google OAuth with email restriction (single authorized user)
- 📊 Analytics: Track clicks, devices, browsers, operating systems, and geographic location
- 🌍 Geolocation: IP-based location tracking with multiple providers and automatic fallback
- 🎨 Modern UI: Clean, responsive interface built with Tailwind CSS
- 📱 QR Codes: Generate QR codes for any short link
- 🔄 Link Management: Toggle active/inactive status, set expiration dates
- ⚡ Fast Redirects: Optimized redirect handling with async click tracking
- 🗄️ PostgreSQL: Reliable database with Drizzle ORM
- Framework: Next.js 16 (App Router)
- UI: React 19, Tailwind CSS
- Database: PostgreSQL (Neon)
- ORM: Drizzle ORM
- Authentication: NextAuth.js with Google OAuth
- Validation: Zod
- Deployment: Vercel-ready
- Node.js 18+ installed
- PostgreSQL database (e.g., Neon, Supabase, or local)
- Google OAuth credentials
git clone <your-repo-url>
cd littlelink
npm installCopy .env.example to .env and fill in your values:
cp .env.example .envRequired environment variables:
DATABASE_URL: Your PostgreSQL connection stringNEXTAUTH_URL: Your app URL (http://localhost:3000 for local dev)NEXTAUTH_SECRET: Generate withopenssl rand -base64 32GOOGLE_CLIENT_ID: From Google Cloud ConsoleGOOGLE_CLIENT_SECRET: From Google Cloud ConsoleALLOWED_USER_EMAIL: Email address allowed to sign in
Optional (for geolocation analytics):
GEOLOCATION_PROVIDER: Comma-separated provider list (e.g.,abstract-api,ipgeolocation)ABSTRACT_API_KEY: From Abstract APIIPGEOLOCATION_API_KEY: From IPGeolocation
- Go to Google Cloud Console
- Create a new project or select existing
- Enable Google+ API
- Go to "Credentials" → "Create Credentials" → "OAuth 2.0 Client ID"
- Add authorized redirect URI:
http://localhost:3000/api/auth/callback/google - Copy Client ID and Client Secret to
.env
Push the schema to your database:
npm run db:pushFor production, use migrations:
npm run db:generate
npm run db:migratenpm run devVisit http://localhost:3000
- Sign in with your authorized Google account
- Enter the original URL
- (Optional) Set a custom short code
- (Optional) Add a title
- Click "Create Short Link"
Your short link will be: http://localhost:3000/abc123
- Toggle Active/Inactive: Temporarily disable links without deleting them
- View Analytics: See click counts and statistics
- Generate QR Codes: Create scannable QR codes for any link
- Delete Links: Permanently remove links (this also deletes all click data)
All API endpoints require authentication except for the redirect handler:
GET /[shortCode]- Redirect to original URL (public)GET /api/links- List all linksPOST /api/links- Create new linkGET /api/links/[id]- Get single linkPATCH /api/links/[id]- Update linkDELETE /api/links/[id]- Delete linkGET /api/links/[id]/qr- Generate QR codeGET /api/analytics/[linkId]- Get analytics
- users: User accounts (NextAuth)
- accounts: OAuth accounts (NextAuth)
- links: Short link mappings
- clicks: Click tracking and analytics
- tags: User-defined tags
- linkTags: Link-to-tag relationships
- orphanedVisits: 404 tracking for non-existent short codes
- apiKeys: API key management
Note: This app uses JWT authentication (no database sessions) and OAuth only (no email verification).
npm run dev # Start development server with Turbopack
npm run build # Build for production
npm start # Start production server
npm run lint # Run ESLint
npm run db:push # Push schema changes to database
npm run db:generate # Generate migrations
npm run db:migrate # Apply migrations
npm run db:studio # Open Drizzle Studio GUI- Push your code to GitHub
- Import project in Vercel
- Add environment variables
- Deploy
Update these for production:
NEXTAUTH_URL=https://your-domain.com
ALLOWED_USER_EMAIL=your-production-email@example.comGeographic analytics are powered by external geolocation APIs with automatic fallback:
- Supports multiple providers: Abstract API, IPGeolocation, and more
- Automatic fallback: If primary provider fails, tries next in chain
- Optional: Works without geolocation (returns null for location data)
- Privacy-friendly: Private/localhost IPs detected locally, not sent to providers
Configure with GEOLOCATION_PROVIDER environment variable. See CLAUDE.md for details.
- Only the email specified in
ALLOWED_USER_EMAILcan sign in - All routes except
/[shortCode]and/auth/*require authentication - API keys table is prepared for future programmatic access
- Click tracking uses fire-and-forget pattern to avoid slowing redirects
MIT
Built with ❤️ using Next.js, React, and Drizzle ORM