A production-ready Next.js template with authentication, database, and email built-in.
Perfect for building modern web applications without the hassle of setting up authentication, databases, or email systems from scratch. Everything is configured and ready to go.
This template gives you a complete full-stack web application with:
- User Authentication - Sign up, log in, password reset, and GitHub OAuth
- Database - Convex database with real-time updates and type safety
- Email System - Password reset emails with beautiful templates
- Modern UI - 50+ pre-built components with dark mode support
- Type Safety - Full TypeScript support throughout
- Developer Experience - Hot reload, linting, formatting all configured
Frontend:
- Next.js 15 - React framework with App Router
- React 19 - Latest React with modern features
- Tailwind CSS v4 - Utility-first styling
- shadcn/ui - Beautiful, accessible components
Backend:
- Convex - Database and serverless functions
- Convex Auth - Authentication system
- Node.js - Server-side runtime for emails
Tools:
- TypeScript - Type safety
- Biome - Fast linter and formatter
- react-email - Email template builder
You'll need:
- Node.js version 18 or higher (download here)
- npm (comes with Node.js)
- A code editor like VS Code
That's it! Everything else is included.
This is the fastest way to get started. Uses Convex's free cloud service.
-
Clone or download this template
-
Install dependencies
npm install
-
Set up your environment
cp .env.sample .env.local
-
Start the development server
npm run dev
-
Open your browser
Visit http://localhost:3000
That's it! The app is now running with a locally-hosted Convex backend. The first time you run npm run dev, it will:
- Create a Convex deployment
- Generate secure authentication keys
- Open the Convex dashboard
- Start the development server
Want complete control? Run everything locally with Docker.
-
Clone or download this template
-
Install dependencies
npm install
-
Start the Docker services
docker compose -f docker-compose.convex.yaml up -d
This starts:
- Convex backend (ports 3210, 3211)
- Convex dashboard (port 6791)
- PostgreSQL database (port 5432)
-
Set up your environment
cp .env.sample .env.local
Edit
.env.localand uncomment the self-hosted section:# Comment out or remove this line: # CONVEX_DEPLOYMENT=anonymous:anonymous-next-leaflet # Uncomment these lines: CONVEX_SELF_HOSTED_URL='http://localhost:3210' CONVEX_SELF_HOSTED_ADMIN_KEY='next-leaflet|017...516'
-
Start the development server
npm run dev
-
Open your browser
Visit http://localhost:3000
Access the Convex dashboard at http://localhost:6791
Once your development server is running, you can:
- Click "Sign Up" or visit http://localhost:3000/register
- Enter your email, name, and password
- You'll be automatically logged in and redirected to the dashboard
- Set up GitHub OAuth (see GitHub OAuth Setup)
- Click "Continue with GitHub" on the login page
- Authorize the app and you're in
- Click "Forgot Password?" on the login page
- Enter your email
- Check your email for the reset link (requires Email Setup)
- View your profile information
- Switch between light and dark themes
- Update your name
- See real-time data updates
next-leaflet/
│
├── src/ # Frontend code
│ ├── app/ # Next.js pages
│ │ ├── (home)/ # Public landing page
│ │ ├── (auth)/ # Login, register, reset pages
│ │ └── dash/ # Protected dashboard pages
│ │
│ ├── components/ # Reusable React components
│ │ └── ui/ # Pre-built UI components
│ │
│ ├── emails/ # Email templates
│ │ └── Reset.tsx # Password reset email
│ │
│ ├── lib/ # Utility functions
│ └── styles/ # Global styles and themes
│
├── convex/ # Backend code
│ ├── schema.ts # Database structure
│ ├── auth.ts # Authentication logic
│ ├── users.ts # User-related functions
│ ├── email.ts # Email sending logic
│ └── _generated/ # Auto-generated types
│
├── .env.local # Your environment variables (not in git)
├── .env.sample # Template for environment variables
└── setup.mjs # Automatic setup script
┌─────────────┐
│ Browser │
└──────┬──────┘
│ 1. User signs up/logs in
↓
┌─────────────────┐
│ Next.js App │
└────────┬────────┘
│ 2. Sends credentials
↓
┌──────────────────┐
│ Convex Auth │ 3. Validates & creates JWT token
└────────┬─────────┘
│ 4. Returns token
↓
┌─────────────────┐
│ Next.js App │ 5. Stores token in cookies
└────────┬────────┘
│ 6. Includes token in all requests
↓
┌──────────────────┐
│ Convex Backend │ 7. Verifies token & returns user data
└──────────────────┘
Protected Routes:
- Any page in
src/app/dash/requires authentication - If not logged in, users are redirected to
/login - If already logged in, visiting
/loginredirects to/dash
Convex gives you a real-time database with automatic type safety.
Define your schema (convex/schema.ts):
import { defineSchema, defineTable } from "convex/server"
import { v } from "convex/values"
export default defineSchema({
tasks: defineTable({
text: v.string(),
completed: v.boolean(),
}),
})Create backend functions (convex/tasks.ts):
import { v } from "convex/values"
import { query, mutation } from "./_generated/server"
// Read data
export const list = query({
args: {},
handler: async (ctx) => {
return await ctx.db.query("tasks").collect()
},
})
// Write data
export const create = mutation({
args: { text: v.string() },
handler: async (ctx, args) => {
await ctx.db.insert("tasks", {
text: args.text,
completed: false
})
},
})Use in your components:
import { useQuery, useMutation } from "convex/react"
import { api } from "@/convex/_generated/api"
export default function TaskList() {
// Auto-updates when data changes!
const tasks = useQuery(api.tasks.list)
const createTask = useMutation(api.tasks.create)
return (
<div>
{tasks?.map(task => (
<div key={task._id}>{task.text}</div>
))}
<button onClick={() => createTask({ text: "New task" })}>
Add Task
</button>
</div>
)
}That's it! No API routes, no REST endpoints, no GraphQL. Just functions.
# Development
npm run dev # Start everything (frontend + backend)
npm run dev:frontend # Start only Next.js (port 3000)
npm run dev:backend # Start only Convex backend
# Production
npm run build # Build for production
npm start # Start production server
# Code Quality
npm run lint # Check code for issues
npm run lint:fix # Auto-fix issues
npm run format # Format all code
# Email Development
npm run email # Preview and edit email templatesAdd one-click "Continue with GitHub" login to your app.
-
Create a GitHub OAuth App
- Go to github.com/settings/developers
- Click "New OAuth App"
- Fill in the form:
- Application name: Your App Name
- Homepage URL:
http://localhost:3000 - Authorization callback URL:
http://localhost:3000/api/auth/callback/github
- Click "Register application"
-
Get your credentials
- Copy the Client ID
- Click "Generate a new client secret" and copy it
-
Add to your environment
Edit
.env.local:AUTH_GITHUB_ID=Ov23li...your-client-id AUTH_GITHUB_SECRET=ghp_...your-client-secret
-
Restart your dev server
# Stop the server (Ctrl+C) and restart npm run dev
The GitHub sign-in button will automatically appear on login and registration pages.
For production: Update the URLs in your GitHub OAuth App settings to your production domain.
Send password reset emails and other transactional emails.
-
Get SMTP credentials
You'll need an SMTP email service. Free options:
-
Add credentials to
.env.localSMTP_HOST=smtp.resend.com SMTP_PORT=587 SMTP_USER=resend SMTP_PASS=re_your_api_key_here MAIL_DEFAULT_NAME="My App" MAIL_DEFAULT_ADDRESS="[email protected]"
-
Restart your dev server
npm run dev
That's it! Password reset emails will now be sent automatically.
Customize email templates:
npm run emailThis opens a preview server at http://localhost:8086 where you can see and edit your email templates in src/emails/.
Click to see all environment variables
Next.js Configuration:
# Your app's URL (change for production)
NEXT_PUBLIC_DOMAIN=http://localhost:3000
# Convex connection (auto-configured in dev)
NEXT_PUBLIC_CONVEX_URL=http://localhost:3210Convex Configuration (choose one):
Option 1 - Cloud (default):
CONVEX_DEPLOYMENT=anonymous:anonymous-next-leafletOption 2 - Self-hosted:
CONVEX_SELF_HOSTED_URL=http://localhost:3210
CONVEX_SELF_HOSTED_ADMIN_KEY=next-leaflet|your-admin-keyGitHub OAuth (optional):
AUTH_GITHUB_ID=Ov23li...
AUTH_GITHUB_SECRET=ghp_...Email SMTP (optional):
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-username
SMTP_PASS=your-password
MAIL_DEFAULT_NAME="Your App"
[email protected]Auto-generated (don't touch):
# These are automatically generated by setup.mjs
JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY----- ..."
JWKS='{"keys":[...]}'This project uses shadcn/ui - a collection of beautiful, accessible components.
Browse available components: ui.shadcn.com
Add a component:
npx shadcn@latest add button
npx shadcn@latest add card
npx shadcn@latest add dialog
npx shadcn@latest add dropdown-menuComponents are added to src/components/ui/ and are fully customizable.
Use in your app:
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
export default function MyPage() {
return (
<Card>
<Button>Click me</Button>
</Card>
)
}Public page (accessible to everyone):
-
Create
src/app/(home)/about/page.tsx:export default function AboutPage() { return ( <div> <h1>About Us</h1> <p>This is a public page</p> </div> ) }
Protected page (requires login):
-
Create
src/app/dash/settings/page.tsx:export default function SettingsPage() { return ( <div> <h1>Settings</h1> <p>This page requires authentication</p> </div> ) }
The middleware automatically protects any route under /dash.
-
Define your schema in
convex/schema.ts:export default defineSchema({ // Existing tables... tasks: defineTable({ text: v.string(), completed: v.boolean(), userId: v.id("users"), }).index("by_user", ["userId"]), })
-
Create backend functions in
convex/tasks.ts:import { v } from "convex/values" import { mutation, query } from "./_generated/server" import { auth } from "./auth" export const list = query({ args: {}, handler: async (ctx) => { const userId = await auth.getUserId(ctx) if (!userId) throw new Error("Not authenticated") return await ctx.db .query("tasks") .withIndex("by_user", (q) => q.eq("userId", userId)) .collect() }, }) export const create = mutation({ args: { text: v.string() }, handler: async (ctx, args) => { const userId = await auth.getUserId(ctx) if (!userId) throw new Error("Not authenticated") await ctx.db.insert("tasks", { text: args.text, completed: false, userId, }) }, })
-
Use in your components:
import { useQuery, useMutation } from "convex/react" import { api } from "@/convex/_generated/api" export default function Tasks() { const tasks = useQuery(api.tasks.list) const createTask = useMutation(api.tasks.create) return ( <div> {tasks?.map(task => ( <div key={task._id}>{task.text}</div> ))} <button onClick={() => createTask({ text: "New task" })}> Add </button> </div> ) }
The types are generated automatically! No manual type definitions needed.
Colors are defined in src/styles/globals.css.
Change the color scheme:
@layer base {
:root {
--background: 0 0% 100%; /* White */
--foreground: 222.2 84% 4.9%; /* Dark text */
--primary: 221.2 83.2% 53.3%; /* Blue */
--primary-foreground: 210 40% 98%; /* Light text on primary */
/* ... more colors */
}
.dark {
--background: 222.2 84% 4.9%; /* Dark */
--foreground: 210 40% 98%; /* Light text */
--primary: 217.2 91.2% 59.8%; /* Lighter blue */
/* ... more colors */
}
}Use the shadcn theme editor: ui.shadcn.com/themes
Copy and paste the generated CSS into globals.css.
Deploy to Vercel (Recommended)
Vercel is made by the creators of Next.js and provides the best deployment experience.
-
Push your code to GitHub
git init git add . git commit -m "Initial commit" git remote add origin https://github.com/yourusername/your-repo.git git push -u origin main
-
Create a Convex production deployment
npx convex deploy
This creates a production Convex backend. Copy the deployment URL shown.
-
Deploy to Vercel
- Go to vercel.com
- Click "Add New Project"
- Import your GitHub repository
- Add environment variables:
CONVEX_DEPLOYMENT- Your Convex deployment URLNEXT_PUBLIC_DOMAIN- Your production URL (e.g.,https://myapp.vercel.app)
- Click "Deploy"
-
Configure GitHub OAuth for production
- Update your GitHub OAuth App callback URL to:
https://your-app.vercel.app/api/auth/callback/github
- Update your GitHub OAuth App callback URL to:
-
Add production SMTP credentials
- Add your SMTP variables to Vercel environment variables
- Or use Convex dashboard to set them
Done! Your app is live.
Deploy to Other Platforms
You can deploy to any platform that supports Next.js:
Platforms:
Steps:
- Create a production Convex deployment:
npx convex deploy - Set these environment variables on your platform:
CONVEX_DEPLOYMENT- Your Convex deployment URLNEXT_PUBLIC_DOMAIN- Your production domainAUTH_GITHUB_IDandAUTH_GITHUB_SECRET(if using GitHub OAuth)- SMTP variables (if using email)
- Deploy your code
Self-Host Everything
Run the entire stack on your own server.
-
Set up your server (Ubuntu/Debian example):
# Install Docker curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh # Install Node.js curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt-get install -y nodejs
-
Clone your repository
git clone https://github.com/yourusername/your-app.git cd your-app npm install -
Start Docker services
docker compose -f docker-compose.convex.yaml up -d
-
Build the Next.js app
npm run build
-
Start the production server
npm start
-
Set up a reverse proxy (nginx example):
server { listen 80; server_name yourdomain.com; location / { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
-
Add SSL with Let's Encrypt
apt-get install certbot python3-certbot-nginx certbot --nginx -d yourdomain.com
Port already in use
If you see Error: Port 3000 is already in use:
Find what's using the port:
# macOS/Linux
lsof -i :3000
# Windows
netstat -ano | findstr :3000Kill the process or use a different port:
# Use a different port
PORT=3001 npm run devConvex connection errors
If the app can't connect to Convex:
-
Check your
.env.localfile- Make sure
NEXT_PUBLIC_CONVEX_URLis set correctly - For cloud: Should be auto-configured
- For self-hosted: Should be
http://localhost:3210
- Make sure
-
Restart the Convex dev server
npx convex dev
-
Clear your browser cache and cookies
-
Check Docker is running (self-hosted only):
docker compose -f docker-compose.convex.yaml ps
Email not sending
If password reset emails aren't sending:
-
Check SMTP configuration in
.env.local- Verify all SMTP variables are set correctly
- Test your SMTP credentials with your provider
-
Check Convex environment variables
npx convex env list
SMTP variables should be there. If not, restart dev server.
-
Check the Convex logs
- Open the Convex dashboard
- Look for error messages in the logs
-
Test with a different SMTP provider
- Try a service like Resend or SendGrid
- They have better debugging tools
Authentication not working
If sign-up or login fails:
-
Check the browser console for error messages
-
Verify JWT keys exist
- Look in
.env.localforJWT_PRIVATE_KEYandJWKS - If missing, delete them and restart:
npm run dev
- Look in
-
Clear all cookies
- Open browser DevTools
- Application → Cookies → Clear all
-
Check Convex auth configuration
- Open
convex/auth.config.ts - Verify
domainmatches yourNEXT_PUBLIC_DOMAIN
- Open
Type errors after schema changes
If you get TypeScript errors after changing your database schema:
-
Restart the Convex dev server
# Stop with Ctrl+C, then: npx convex dev -
Restart your IDE (VS Code, etc.)
-
Clear generated files
rm -rf convex/_generated npx convex dev
Is this free to use?
Yes! This template is MIT licensed - use it for personal or commercial projects.
Free tiers available:
- Convex: 1GB storage, 1M function calls/month
- Vercel: Unlimited personal projects
- Most SMTP services: 100-3000 emails/month free
Do I need to know React/Next.js?
Basic React knowledge helps, but you can learn as you go. The template is structured to be beginner-friendly.
Great resources:
Can I use a different database?
This template is built specifically for Convex. To use PostgreSQL, MongoDB, or others, you'd need to:
- Replace Convex functions with API routes
- Set up your own authentication system
- Handle real-time updates differently
We recommend trying Convex first - it's simpler than traditional databases.
Can I use a different CSS framework?
Yes! You can replace Tailwind with:
- CSS Modules
- Styled Components
- Sass/SCSS
- Vanilla CSS
Just remove Tailwind from package.json and configure your preferred styling solution.
How do I add more OAuth providers?
Convex Auth supports many providers. Example for Google:
-
Install the provider:
npm install @auth/core
-
Add to
convex/auth.ts:import Google from "@auth/core/providers/google" export const { auth, signIn, signOut } = convexAuth({ providers: [GitHub, Google, Password({ ... })], })
-
Add credentials to
.env.local:AUTH_GOOGLE_ID=your-google-client-id AUTH_GOOGLE_SECRET=your-google-client-secret
How do I add file uploads?
Convex has built-in file storage:
-
Add to your mutation:
export const generateUploadUrl = mutation({ handler: async (ctx) => { return await ctx.storage.generateUploadUrl() }, })
-
Upload in your component:
const generateUploadUrl = useMutation(api.files.generateUploadUrl) async function handleUpload(file: File) { const uploadUrl = await generateUploadUrl() await fetch(uploadUrl, { method: "POST", body: file, }) }
Can I use this for mobile apps?
Yes! Convex works with:
- React Native
- Expo
- iOS (Swift)
- Android (Kotlin)
The backend stays the same. Just change the frontend framework.
- Next.js Docs - Learn Next.js features and API
- Convex Docs - Database and backend functions
- Convex Auth - Authentication system
- Tailwind CSS - Styling framework
- shadcn/ui - UI component library
- Convex Discord - Get help from the community
- Next.js Discord - Next.js community
- Stack Overflow - Ask technical questions
Found a bug or have a feature suggestion? Contributions are welcome!
- Fork the repository
- Create a feature branch:
git checkout -b my-feature - Make your changes
- Run linting:
npm run lint:fix - Commit your changes:
git commit -m "Add some feature" - Push to the branch:
git push origin my-feature - Open a pull request
MIT License - feel free to use this template for any project.
If you find this template helpful, please:
- ⭐ Star this repository
- 🐛 Report bugs by opening an issue
- 💡 Suggest features by opening an issue
- 📖 Improve documentation by submitting a PR
Ready to build something amazing?
npm install
npm run devHappy coding! 🚀
