Skip to content

martinstefanovic/nest-next-starter-template

Repository files navigation

Full-Stack NestJS + Next.js Monorepo Template

A production-ready full-stack TypeScript monorepo featuring NestJS backend API and Next.js frontend with authentication, i18n, and modern development tools.

Table of Contents

Tech Stack

Backend

  • NestJS - Progressive Node.js framework
  • TypeORM - TypeScript ORM with Active Record pattern
  • PostgreSQL - Relational database
  • JWT - Authentication with access/refresh tokens
  • Passport - Authentication middleware
  • Swagger - API documentation
  • Class Validator - DTO validation
  • i18n - Internationalization support
  • Sharp - Image processing
  • Helmet - Security headers

Frontend

  • Next.js 16 - React framework with App Router
  • React 19 - Latest React with Server Components
  • TanStack Query - Server state management
  • React Hook Form - Form management
  • Zod - Schema validation
  • next-intl - Internationalization
  • Tailwind CSS v4 - Utility-first CSS
  • shadcn/ui - UI component library
  • Sonner - Toast notifications

Monorepo Tools

  • Turborepo - Build system and task runner
  • pnpm - Fast, disk space efficient package manager
  • TypeScript - Type safety across all packages
  • Shared Packages - API client, design system, env config, interfaces

Project Structure

nest-example/
├── apps/
│   ├── backend/                 # NestJS API
│   │   ├── src/
│   │   │   ├── common/          # Shared utilities, guards, decorators
│   │   │   ├── database/        # TypeORM config, migrations, seeding
│   │   │   ├── modules/
│   │   │   │   ├── auth/        # Authentication (JWT, guards, strategies)
│   │   │   │   ├── users/       # User management
│   │   │   │   └── ...
│   │   │   └── main.ts          # App entry point
│   │   ├── .env                 # Backend environment variables
│   │   └── package.json
│   │
│   └── web/                     # Next.js Frontend
│       ├── src/
│       │   ├── app/             # App Router pages
│       │   │   └── [locale]/    # i18n routing
│       │   │       ├── (main)/
│       │   │       │   ├── (public)/   # Public pages (auth)
│       │   │       │   └── (private)/  # Protected pages
│       │   ├── components/      # Shared UI components
│       │   ├── context/         # React contexts (auth, theme)
│       │   ├── hooks/           # Custom React hooks
│       │   ├── lib/             # Utilities, actions, API client
│       │   ├── i18n/            # Internationalization config
│       │   └── proxy.ts         # Middleware (auth, i18n routing)
│       ├── .env.local           # Frontend environment variables
│       └── package.json
│
├── packages/
│   ├── api-client/              # Auto-generated TypeScript API client
│   ├── design/                  # Shared UI components (shadcn/ui)
│   ├── env/                     # Environment variable schemas
│   └── interfaces/              # Shared TypeScript interfaces
│
├── tooling/                     # ESLint, TypeScript configs
├── turbo.json                   # Turborepo configuration
├── pnpm-workspace.yaml          # pnpm workspace definition
└── package.json                 # Root package with scripts

Prerequisites

Before you begin, ensure you have the following installed:

Getting Started

Step 1: Clone the Repository

git clone <your-repository-url>
cd nest-example

Step 2: Install Dependencies

# Install all dependencies for all packages
pnpm install

This will install dependencies for:

  • Root workspace
  • Backend application
  • Frontend application
  • All shared packages

Step 3: Set Up PostgreSQL Database

Option A: Local PostgreSQL Installation

  1. Start PostgreSQL service:
# macOS (Homebrew)
brew services start postgresql

# Linux (systemd)
sudo systemctl start postgresql

# Windows
# Start via Services or pgAdmin
  1. Create a database:
# Connect to PostgreSQL
psql postgres

# Create database and user
CREATE DATABASE nestapp;
CREATE USER your_username WITH PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE nestapp TO your_username;
\q

Option B: Docker PostgreSQL

docker run --name postgres-dev \
  -e POSTGRES_PASSWORD=your_password \
  -e POSTGRES_USER=your_username \
  -e POSTGRES_DB=nestapp \
  -p 5432:5432 \
  -d postgres:16

Step 4: Configure Environment Variables

Backend Environment

Create/update apps/backend/.env:

cd apps/backend
cp .env.example .env

Edit apps/backend/.env:

# Application
NODE_ENV=development
PORT=3030

# Database (PostgreSQL)
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=your_username        # Change this
DB_PASSWORD=your_password        # Change this
DB_DATABASE=nestapp
DB_SYNCHRONIZE=true              # Auto-sync schema (dev only!)
DB_LOGGING=true                  # Log SQL queries

# JWT Secrets (CHANGE THESE!)
JWT_ACCESS_SECRET=your-super-secret-access-key-change-this-in-production
JWT_REFRESH_SECRET=your-super-secret-refresh-key-change-this-in-production
JWT_ACCESS_EXPIRATION=7d         # Access token expiration
JWT_REFRESH_EXPIRATION=7d        # Refresh token expiration

# CORS
CORS_ORIGIN=http://localhost:3000

# File Upload
MAX_FILE_SIZE=5242880            # 5MB in bytes
UPLOAD_DIR=./uploads

# Rate Limiting
THROTTLE_TTL=60                  # Time window in seconds
THROTTLE_LIMIT=100               # Max requests per window

Frontend Environment

Create/update apps/web/.env.local:

cd apps/web
cp .example.env .env.local

Edit apps/web/.env.local:

# API URLs
API_URL="http://localhost:3030"              # Backend URL (server-side)
NEXT_PUBLIC_API_URL="http://localhost:3000"  # Frontend proxy URL (client-side)
NEXT_PUBLIC_BACKEND_URL="http://localhost:3030"

Step 5: Initialize the Database

The backend uses TypeORM with auto-synchronization enabled in development. When you start the backend for the first time, it will automatically create all tables.

Optionally, seed the database with sample data:

pnpm db:seed

This creates:

  • Admin user: admin@example.com / Admin123!
  • Regular user: user@example.com / User123!

Step 6: Start Development Servers

Option A: Run All Apps Simultaneously (Recommended)

# From root directory
pnpm dev

This starts:

Option B: Run Apps Individually

Terminal 1 - Backend:

cd apps/backend
pnpm dev

Terminal 2 - Frontend:

cd apps/web
pnpm dev

Step 7: Verify Installation

  1. Backend API: Open http://localhost:3030/api

    • You should see the Swagger API documentation
  2. Frontend: Open http://localhost:3000

    • You should see the homepage
    • Navigate to /auth/sign-in to log in
  3. Test Login:

    • Email: admin@example.com
    • Password: Admin123!

Development

Running the Applications

# Run both frontend and backend in development mode
pnpm dev

# Build all packages and applications
pnpm build

# Run production build
pnpm start

# Run linting across all packages
pnpm lint

# Run type checking
pnpm typecheck

Working with the Backend

# Start backend in watch mode
cd apps/backend
pnpm dev

# Build backend
pnpm build

# Run production mode
pnpm start

# Run tests
pnpm test

# Run tests in watch mode
pnpm test:watch

# Run E2E tests
pnpm test:e2e

# Generate TypeORM migration
pnpm typeorm migration:generate src/database/migrations/MigrationName

# Run migrations
pnpm typeorm migration:run

# Revert last migration
pnpm typeorm migration:revert

# Seed database
pnpm db:seed

Working with the Frontend

# Start frontend in development mode
cd apps/web
pnpm dev

# Build for production
pnpm build

# Run production build locally
pnpm start

# Check TypeScript types
pnpm check-types

# Lint code
pnpm lint

Working with Shared Packages

API Client (Auto-generated)

The API client is automatically generated from the backend's Swagger documentation:

# Generate API client from backend OpenAPI spec
pnpm generate:api

# Build API client package
pnpm build:api-client

When to regenerate:

  • After adding new API endpoints
  • After modifying DTOs or response types
  • After changing API routes

Design System

The design system package (@myorg/design) contains shared UI components:

cd packages/design

# Add a new component
pnpm add-component button

# Build design system
pnpm build

Database Management

Creating Migrations

When you modify entities, create a migration:

cd apps/backend

# Generate migration from entity changes
pnpm typeorm migration:generate src/database/migrations/AddUserProfile

# Run pending migrations
pnpm typeorm migration:run

Seeding Data

# Seed database with initial data
pnpm db:seed

# Or from root
pnpm --filter @nest-example/backend db:seed

Git Hooks (Husky)

This project uses Husky to enforce code quality through git hooks.

Automatic Setup

Git hooks are automatically installed when you run pnpm install (via the prepare script). You don't need to do anything manually!

What Hooks Are Enabled?

Pre-commit Hook (.husky/pre-commit):

  • Runs ESLint on both backend and frontend
  • Automatically fixes auto-fixable issues
  • Prevents commit if there are linting errors
  • Warnings won't block commits

Commit Message Hook (.husky/commit-msg):

Conventional Commit Format

Your commit messages must follow this format:

<type>: <description>

[optional body]

[optional footer]

Valid types:

  • feat - New feature
  • fix - Bug fix
  • docs - Documentation changes
  • style - Code style changes (formatting)
  • refactor - Code refactoring
  • perf - Performance improvements
  • test - Adding or updating tests
  • build - Build system or dependencies
  • ci - CI/CD changes
  • chore - Other changes
  • revert - Revert a previous commit

Examples:

git commit -m "feat: add user profile page"
git commit -m "fix: resolve login redirect issue"
git commit -m "docs: update README with setup instructions"
git commit -m "refactor: simplify authentication logic"

Bypassing Hooks (Not Recommended)

If you absolutely need to skip hooks (e.g., WIP commit):

git commit --no-verify -m "wip: work in progress"

Note: This is not recommended as it bypasses code quality checks.

Manual Hook Installation

If hooks aren't working, you can manually reinstall them:

pnpm prepare

Project Architecture

Authentication Flow

  1. User submits credentials via frontend login form
  2. Frontend calls /api/auth/login server action
  3. Server action proxies request to backend API
  4. Backend validates credentials, generates JWT tokens
  5. Frontend stores tokens in httpOnly cookies
  6. Middleware (proxy.ts) validates tokens on each request
  7. Protected pages check authentication state

API Client Pattern

// Frontend: Using the auto-generated API client
import { createServerApi } from '@myorg/api-client';

const api = createServerApi({
  baseUrl: env.API_URL,
  token: 'optional-auth-token',
});

const users = await api.api.usersQueryControllerFindAll();

Internationalization

The project supports multiple languages (English, Serbian):

Backend:

  • Uses nestjs-i18n for API responses
  • Translation files: apps/backend/src/i18n/{lang}/

Frontend:

  • Uses next-intl for UI translations
  • Translation files: apps/web/src/i18n/messages/{lang}.json
  • URL structure: /en/... or /sr/...

Middleware & Route Protection

The Next.js middleware (apps/web/src/proxy.ts) handles:

  • Authentication checks (JWT validation)
  • Role-based access control (ADMIN routes)
  • Locale routing (i18n)
  • Security headers

Protected route patterns:

  • /admin/* - Requires ADMIN role
  • All routes except public routes - Require authentication

Available Scripts

Root Level

Command Description
pnpm dev Run all apps in development mode
pnpm build Build all packages and apps
pnpm start Start all apps in production mode
pnpm lint Lint all packages
pnpm test Run tests in all packages
pnpm typecheck Type-check all packages
pnpm clean Remove all node_modules and build artifacts
pnpm generate:api Generate API client from OpenAPI spec
pnpm db:seed Seed the database

Backend (apps/backend)

Command Description
pnpm dev Start in watch mode
pnpm build Build for production
pnpm start Start production server
pnpm test Run unit tests
pnpm test:e2e Run E2E tests
pnpm typeorm Run TypeORM CLI commands
pnpm db:seed Seed database

Frontend (apps/web)

Command Description
pnpm dev Start Next.js dev server
pnpm build Build for production
pnpm start Start production server
pnpm lint Lint code
pnpm check-types Type-check without building

Common Issues

Issue: "Cannot connect to database"

Solution:

  1. Ensure PostgreSQL is running: psql -U postgres -c "SELECT 1"
  2. Verify database exists: psql -U postgres -l
  3. Check credentials in apps/backend/.env
  4. Ensure DB_HOST=localhost and DB_PORT=5432

Issue: "Port 3000 or 3030 already in use"

Solution:

# Find process using port
lsof -ti:3000 # or :3030

# Kill the process
kill -9 <PID>

# Or change ports in .env files

Issue: "Module not found" errors

Solution:

# Clean install
pnpm clean
pnpm install

# Rebuild packages
pnpm build

Issue: "API client types are outdated"

Solution:

# Regenerate API client after backend changes
pnpm generate:api

Issue: "Database schema out of sync"

Solution:

cd apps/backend

# Development: Let TypeORM sync (if DB_SYNCHRONIZE=true)
# Just restart the server

# Production: Create and run migration
pnpm typeorm migration:generate src/database/migrations/SyncSchema
pnpm typeorm migration:run

Development Tips

Hot Reload

Both frontend and backend support hot reload:

  • Backend: NestJS watch mode restarts on file changes
  • Frontend: Next.js Fast Refresh updates on save

API Documentation

Access Swagger docs at http://localhost:3030/api when backend is running.

Environment Variables

  • Never commit .env or .env.local files
  • Use .env.example as templates
  • Update both when adding new variables

Database Migrations vs Synchronize

  • Development: Use DB_SYNCHRONIZE=true for auto-sync
  • Production: ALWAYS use migrations, set DB_SYNCHRONIZE=false

Code Generation

After modifying backend DTOs or endpoints:

pnpm generate:api

This keeps frontend types in sync with backend API.

Production Deployment

Backend

  1. Set environment variables:
NODE_ENV=production
DB_SYNCHRONIZE=false
  1. Build and run:
pnpm build
pnpm start
  1. Run migrations:
pnpm typeorm migration:run

Frontend

  1. Build:
pnpm build
  1. Start:
pnpm start

Or deploy to Vercel/Netlify directly.

Claude Code Skills (AI-Assisted Development)

This project includes custom Claude Code skills that automate feature scaffolding. When working with Claude Code, you can generate complete features by describing what you need in natural language.

Available Skills

Command Description
/project:create-full-feature End-to-end: backend module + frontend UI pages + migration
/project:create-backend-module NestJS module (entity, DTOs, actions, controllers, service, i18n)
/project:create-frontend-feature Next.js feature pages (list, edit, create with table/forms/filters)
/project:create-entity TypeORM entity with database registration

Usage

Explicit invocation:

/project:create-full-feature A blog module with posts that have title, body,
status (DRAFT/PUBLISHED), and belong to categories

Natural language (auto-detected): Simply describe what you want - Claude will automatically detect the intent and invoke the right skill:

"I want a notifications feature where admins can send notifications to users"
"Add an API for managing products with name, price, and category"
"Create admin pages for the orders module"

How Skills Work

  • Project skills (.claude/commands/) define what to build and which project patterns to follow
  • They can be combined with execution modes like autopilot for fully autonomous feature generation
  • All generated code follows the project's conventions documented in CLAUDE.md
  • Skills reference the Users module (apps/backend/src/modules/users/) as the canonical pattern

What Gets Generated

A full feature (/project:create-full-feature) creates:

Backend (apps/backend/src/modules/{module}/):

  • Entity with proper field ordering and indexes
  • DTOs (Create, Update, Query with filters, Response)
  • Actions (Create, Update, Delete) with business logic
  • Service with QueryHelper pagination
  • Controllers (Query + Command) with Swagger docs
  • i18n files (en.json, sr.json)
  • Module registration in database.module.ts and app.module.ts

Frontend (apps/web/src/app/[locale]/(main)/(private)/{section}/{feature}/):

  • List page with server-side table and filters
  • Edit page with form, Zod schema, and server actions
  • Create page (optional) with form and validation
  • All types imported from @myorg/api-client

Learn More

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors