Skip to content

Repository files navigation

Next.js Starter Template

A production-ready Next.js 15 starter template with authentication, form handling, and a scalable architecture.

πŸš€ Features

  • ⚑ Next.js 15.5 with App Router and Turbopack
  • πŸ” Authentication - Cookie-based auth with protected routes
  • πŸ“ Form Handling - TanStack Form + Zod validation
  • 🎨 UI Components - shadcn/ui + Tailwind CSS 4
  • πŸ”„ State Management - TanStack Query v5 + Zustand for client state
  • 🎯 TypeScript - Full type safety with enums
  • πŸͺ Custom Hooks - Reusable logic patterns
  • πŸ“± Responsive - Mobile-first design
  • πŸŒ™ Toast Notifications - Sonner for user feedback
  • 🎨 Theme Support - Next Themes for dark/light mode

πŸ“¦ Tech Stack

  • Framework: Next.js 15.5.6
  • Language: TypeScript 5
  • Styling: Tailwind CSS 4 + tw-animate-css
  • UI Library: Radix UI + shadcn/ui
  • Forms: TanStack Form 1.23 + Zod 4.1
  • Data Fetching: TanStack Query 5.90 + Axios 1.13
  • State Management: Zustand 5.0
  • Icons: Lucide React
  • Notifications: Sonner 2.0

🏁 Getting Started

Prerequisites

  • Node.js 20+ and pnpm (or npm/yarn/bun)
  • Docker (optional, for containerized deployment)

Installation

  1. Clone the repository
git clone <your-repo-url>
cd nextjs-template
  1. Install dependencies
pnpm install
  1. Set up environment variables
cp .env.example .env

Edit .env with your configuration.

  1. Run the development server
pnpm dev
  1. Open http://localhost:3000

The app will hot-reload as you edit files.

πŸ“ Project Structure

nextjs-template/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app/                    # Next.js App Router (routes & API)
β”‚   β”‚   β”œβ”€β”€ page.tsx           # Home page (/)
β”‚   β”‚   β”œβ”€β”€ layout.tsx         # Root layout
β”‚   β”‚   β”œβ”€β”€ globals.css        # Global styles
β”‚   β”‚   β”œβ”€β”€ favicon.ico        # App favicon
β”‚   β”‚   β”œβ”€β”€ auth/              # Auth routes (/auth/*)
β”‚   β”‚   β”‚   β”œβ”€β”€ page.tsx       # Auth wrapper page
β”‚   β”‚   β”‚   β”œβ”€β”€ login/         # Login page
β”‚   β”‚   β”‚   └── register/      # Register page
β”‚   β”‚   β”œβ”€β”€ user/              # Protected routes (/user/*)
β”‚   β”‚   β”‚   └── page.tsx       # User dashboard
β”‚   β”‚   └── api/               # API endpoints
β”‚   β”‚       └── auth/          # Auth API routes
β”‚   β”‚           β”œβ”€β”€ login/     # POST /api/auth/login
β”‚   β”‚           β”œβ”€β”€ register/  # POST /api/auth/register
β”‚   β”‚           β”œβ”€β”€ logout/    # POST /api/auth/logout
β”‚   β”‚           └── me/        # GET /api/auth/me
β”‚   β”œβ”€β”€ modules/                # Feature modules
β”‚   β”‚   β”œβ”€β”€ auth/              # Auth feature
β”‚   β”‚   β”‚   β”œβ”€β”€ auth-page.tsx  # Auth layout component
β”‚   β”‚   β”‚   └── _components/   # Private auth components
β”‚   β”‚   β”‚       β”œβ”€β”€ login-form.tsx
β”‚   β”‚   β”‚       └── register-form.tsx
β”‚   β”‚   β”œβ”€β”€ home/              # Home page feature
β”‚   β”‚   β”‚   └── home-page.tsx
β”‚   β”‚   └── user/              # User dashboard feature
β”‚   β”‚       └── dashboard-page.tsx
β”‚   β”œβ”€β”€ components/             # Reusable UI components
β”‚   β”‚   β”œβ”€β”€ ui/                # shadcn/ui base components
β”‚   β”‚   β”‚   β”œβ”€β”€ button.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ card.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ field.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ input.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ input-group.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ label.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ separator.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ sonner.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ tabs.tsx
β”‚   β”‚   β”‚   └── textarea.tsx
β”‚   β”‚   └── custom/            # Custom components
β”‚   β”‚       └── link.tsx
β”‚   β”œβ”€β”€ hooks/                  # Custom React hooks
β”‚   β”‚   β”œβ”€β”€ index.ts           # Hooks barrel export
β”‚   β”‚   └── use-toggle.ts      # Toggle hook
β”‚   β”œβ”€β”€ services/               # API service layer (TanStack Query)
β”‚   β”‚   β”œβ”€β”€ auth-queries.ts    # Read operations (GET)
β”‚   β”‚   └── auth-mutations.ts  # Write operations (POST/PUT/DELETE)
β”‚   β”œβ”€β”€ schemas/                # Zod validation schemas
β”‚   β”‚   └── auth.schema.ts     # Auth form schemas
β”‚   β”œβ”€β”€ types/                  # TypeScript type definitions
β”‚   β”‚   └── auth.type.ts       # Auth types
β”‚   β”œβ”€β”€ enums/                  # TypeScript enums
β”‚   β”‚   └── user-role.enum.ts  # User role enum
β”‚   β”œβ”€β”€ store/                  # Zustand stores for client state
β”‚   β”‚   β”œβ”€β”€ index.ts           # Store barrel export
β”‚   β”‚   └── counter.store.ts   # Example counter store
β”‚   β”œβ”€β”€ lib/                    # Utilities and configured libraries
β”‚   β”‚   β”œβ”€β”€ axios.ts           # Axios instance config
β”‚   β”‚   └── utils.ts           # Utility functions (cn, etc.)
β”‚   β”œβ”€β”€ providers/              # React context providers
β”‚   β”‚   └── react-query-provider.tsx
β”‚   └── middleware.ts           # Next.js middleware (auth protection)
β”œβ”€β”€ public/                     # Static assets
└── ...config files             # See below for details

βš™οΈ Configuration Files

File Purpose
next.config.ts Next.js configuration
tsconfig.json TypeScript configuration
tailwind.config.ts Tailwind CSS configuration
postcss.config.mjs PostCSS configuration
eslint.config.mjs ESLint configuration
.prettierrc Prettier code formatting
components.json shadcn/ui configuration
dockerfile Docker image definition
docker-compose.yml Docker Compose setup
.env.example Environment variables template

πŸ“‚ Folder Purposes

Folder Purpose Example
/app Next.js routes and API endpoints app/auth/login/page.tsx
/modules Feature-specific code modules/auth/_components/login-form.tsx
/components Reusable UI components components/ui/button.tsx
/hooks Custom React hooks hooks/use-toggle.ts
/services API calls with TanStack Query services/auth-mutations.ts
/schemas Zod validation schemas schemas/auth.schema.ts
/types TypeScript types types/auth.type.ts
/store Zustand stores for client state store/counter.store.ts
/providers React context providers providers/react-query-provider.tsx

Key Conventions

  • Files/Folders: kebab-case (e.g., login-form.tsx)
  • Components: PascalCase (e.g., LoginForm)
  • Functions/Variables: camelCase (e.g., useAuthLogin)
  • Private folders: _components/ (module-specific, not reusable)
  • Imports: Use @/ alias (e.g., import { Button } from '@/components/ui/button')

πŸ› οΈ Available Scripts

pnpm dev          # Start development server with Turbopack
pnpm build        # Build for production with Turbopack
pnpm start        # Start production server
pnpm lint         # Run ESLint

Note: This template uses Turbopack for both development and production builds for faster performance.

πŸ”‘ Authentication Flow

This template includes a complete authentication system:

  1. Login/Register - Forms with validation at /auth/login and /auth/register
  2. Cookie-based Auth - HTTP-only cookies for security
  3. Protected Routes - Middleware protects /user/* routes
  4. Auto-redirect - Logged-in users can't access auth pages
  5. User Query - useAuthUser() hook fetches current user

API Routes

  • POST /api/auth/login - User login
  • POST /api/auth/register - User registration
  • POST /api/auth/logout - User logout
  • GET /api/auth/me - Get current user

🎨 Adding New Features

Example: Adding a Blog Feature

  1. Create module structure:
mkdir -p src/modules/blog/_components
  1. Create page component:
// src/modules/blog/blog-page.tsx
export default function BlogPage() {
  return <div>Blog</div>;
}
  1. Create route:
// src/app/blog/page.tsx
import BlogPage from '@/modules/blog/blog-page';
export default BlogPage;
  1. Add services, schemas, and types as needed:
src/services/blog-queries.ts
src/services/blog-mutations.ts
src/schemas/blog.schema.ts
src/types/blog.type.ts

🧩 Custom Hooks

useToggle

Toggle boolean state with ease:

import { useToggle } from '@/hooks';

const [isOpen, toggle] = useToggle(false);

<Button onClick={toggle}>Toggle</Button>

πŸ”’ Enums

Note: The enums in src/enums/ are provided as examples. Replace or extend them to fit your application's needs.

TypeScript enums are placed in the src/enums/ folder for better organization.

UserRole Enum

Define user roles with helper functions:

import { UserRole, isAdminRole } from '@/enums/user-role.enum';

const userRole = UserRole.ADMIN;
if (isAdminRole(userRole)) {
    // Admin-specific logic
}

πŸ—‚οΈ State Management

Zustand Stores

Note: The store in src/store/ is provided as an example. Replace or extend it with your own stores as needed.

Client-side state is managed with Zustand stores in src/store/.

Counter Store Example

import { useCounterStore } from '@/store';

function CounterComponent() {
    const { count, increment, decrement, reset } = useCounterStore();

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={increment}>+</button>
            <button onClick={decrement}>-</button>
            <button onClick={reset}>Reset</button>
        </div>
    );
}

When to Use Zustand vs TanStack Query

  • Zustand: Client-side state (UI state, local preferences, temporary data)
  • TanStack Query: Server state (API data, caching, synchronization)

Why separate modules/ and components/?

  • Modules = Feature-specific components (used once)
  • Components = Reusable components (used across features)

Why separate queries and mutations?

  • Clearer separation of read vs write operations
  • Easier to locate specific API calls
  • Better organization as the app scales

Why _components/ with underscore?

  • Signals "private/internal use only"
  • Prevents accidental reuse of feature-specific components
  • Keeps module boundaries clear

Why separate schemas/ and types/?

  • Schemas = Runtime validation (Zod)
  • Types = Compile-time types (TypeScript)
  • Often both are needed for the same data structure

πŸ”’ Security Features

  • βœ… HTTP-only cookies for auth tokens
  • βœ… Zod validation on all forms
  • βœ… CSRF protection ready (extend API routes)
  • βœ… Middleware route protection
  • βœ… Type-safe API calls

πŸ“š Learn More

πŸš€ Deployment

Option 1: Docker Compose (Recommended - Easiest)

1. Create docker-compose.yml:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - JWT_SECRET=${JWT_SECRET}
      - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
    restart: unless-stopped

2. Create .env file:

JWT_SECRET=your-secret-key
NEXT_PUBLIC_API_URL=http://localhost:3000/api

3. Run:

docker-compose up -d
docker-compose logs -f  # View logs
docker-compose down     # Stop

Option 2: Docker CLI (Manual Method)

If you prefer more control or don't want to use Docker Compose:

Build the image:

docker build -t nextjs-template .

Run the container:

# Basic
docker run -p 3000:3000 nextjs-template

# With environment file
docker run -p 3000:3000 --env-file .env nextjs-template

# Background mode
docker run -d -p 3000:3000 --name my-app nextjs-template
docker logs -f my-app

Option 3: VPS Deployment (Ubuntu/Debian)

  1. Install dependencies:
# Install Node.js 22
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs

# Install pnpm
sudo npm install -g pnpm

# Install PM2 for process management
sudo npm install -g pm2
  1. Clone and setup:
git clone <your-repo-url>
cd nextjs-template
pnpm install
  1. Configure environment:
cp .env.example .env
nano .env  # Edit with your values
  1. Build the application:
pnpm build
  1. Start with PM2:
pm2 start npm --name "nextjs-template" -- start
pm2 save
pm2 startup  # Follow the instructions to enable startup on boot
  1. Setup Nginx reverse proxy:
server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  1. Enable site and reload Nginx:
sudo ln -s /etc/nginx/sites-available/nextjs-template /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
  1. Setup SSL with Certbot (optional):
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com

Environment Variables

Make sure to set these in your deployment environment. See .env.example for the complete list of required variables.

Monitoring and Logs

With PM2:

pm2 logs nextjs-template     # View logs
pm2 status                    # Check status
pm2 restart nextjs-template   # Restart app

With Docker:

docker logs -f <container-id>
docker stats

πŸ“ License

MIT

About

Next JS starter template

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages