A production-ready NestJS boilerplate with Domain-Driven Design (DDD), Hexagonal Architecture (Ports & Adapters), Prisma ORM, and Docker support — built for teams who care about scalability, maintainability, and code quality.
- Features
- Tech Stack
- Project Structure
- Architecture Overview
- Getting Started
- Database
- Code Quality
- License
- ✅ Domain-Driven Design (DDD) — clear separation of domain, application, and infrastructure layers
- ✅ Hexagonal Architecture (Ports & Adapters) — domain at the center, isolated from frameworks and databases via explicit ports and adapters
- ✅ Prisma ORM — type-safe database access with auto-generated client
- ✅ Value Objects — strongly-typed domain primitives (e.g.
UserId) - ✅ Repository Pattern — abstract domain repositories with Prisma implementations
- ✅ Domain Mappers — clean mapping between Prisma models and domain entities
- ✅ Shared Module — reusable infrastructure services (Prisma, base value objects)
- ✅ Docker & Docker Compose — containerized development and deployment
- ✅ ESLint + Prettier — enforced code style on every commit via Husky pre-commit hooks
- ✅ TypeScript — strict typing throughout the entire codebase
| Layer | Technology |
|---|---|
| Framework | NestJS |
| Language | TypeScript |
| ORM | Prisma |
| Runtime | Node.js |
| Container | Docker / Docker Compose |
| Linter | ESLint (flat config) |
| Formatter | Prettier |
| Git Hooks | Husky |
src/
├── app.module.ts # Root application module
├── main.ts # Application entry point
│
├── contexts/ # Bounded contexts (DDD)
│ └── iam/ # Identity & Access Management context
│ ├── iam.module.ts
│ └── users/
│ ├── domain/ # Pure domain logic (no framework dependencies)
│ │ ├── user.repository.ts # Abstract repository interface
│ │ ├── entities/
│ │ │ └── user.entity.ts # User domain entity
│ │ └── value-objects/
│ │ └── user-id.vo.ts # UserId value object
│ └── infrastructure/ # Framework & DB implementations
│ ├── mappers/
│ │ └── user.mapper.ts # Prisma ↔ Domain mapper
│ └── repositories/
│ └── prisma-user.repository.ts # Prisma implementation
│
└── shared/ # Cross-cutting concerns
├── shared.module.ts
├── infrastructure/
│ └── prisma/
│ └── prisma.service.ts # PrismaClient wrapper
└── value-objects/
└── base-id.vo.ts # Base class for ID value objects
prisma/
└── schema.prisma # Database schema definition
This starter combines Domain-Driven Design (DDD) with Hexagonal Architecture (Ports & Adapters). The domain sits at the center and is completely isolated from the outside world — it never depends on NestJS, Prisma, or any external library. All communication flows through Ports (interfaces defined in the domain) and Adapters (concrete implementations in the infrastructure layer).
┌─────────────────────────────────┐
│ DOMAIN CORE │
│ │
┌────────────┐ │ Entities · Value Objects │ ┌──────────────────┐
│ NestJS │──────▶│ │──────▶│ Prisma Database │
│ Controllers│ │ «Port» │ │ (Adapter) │
│ (Adapter) │ │ UserRepository (interface) │ │ PrismaUser │
└────────────┘ │ │ │ Repository │
│ No framework / DB dependencies │ └──────────────────┘
└─────────────────────────────────┘
| Concept | Role | Example |
|---|---|---|
| Port | Interface defined in the domain layer | user.repository.ts |
| Adapter (Driven) | Infrastructure implementation of a Port | prisma-user.repository.ts |
| Mapper | Translates between DB models and domain entities | user.mapper.ts |
| Value Object | Strongly-typed domain primitive with built-in validation | user-id.vo.ts, base-id.vo.ts |
| Bounded Context | Self-contained domain module | contexts/iam/ |
- Domain entities are plain TypeScript classes — zero dependency on Prisma or NestJS.
- Repository interfaces (Ports) live inside the domain layer, not the infrastructure layer. The domain dictates the contract; infrastructure fulfills it.
- Prisma repositories (Adapters) implement domain ports and are registered in NestJS DI as the concrete providers.
- Mappers handle all conversion between Prisma models and domain entities, so neither layer is polluted by the other's shape.
- Value Objects (like
UserId) encapsulate validation and identity logic, preventing primitive obsession. - Bounded contexts under
src/contexts/allow the codebase to scale horizontally into independent domain modules without coupling.
- Node.js >= 18
- npm >= 9
- Docker & Docker Compose (optional, for containerized setup)
- A supported database (PostgreSQL recommended — configure via
DATABASE_URL)
# Clone the repository
git clone https://github.com/8eyond/infinite-nestjs-advanced-starter.git
cd infinite-nestjs-advanced-starter
# Install dependencies
npm installCopy the example env file and fill in your values:
cp .env.example .env| Variable | Description | Example |
|---|---|---|
DATABASE_URL |
Prisma connection string | postgresql://user:pass@localhost:5432/mydb |
PORT |
HTTP port the app listens on | 3000 |
See
.env.examplefor the full list of required variables.
# Development (watch mode)
npm run start:dev
# Production build
npm run build
npm run start:prod
# Debug mode
npm run start:debug# Start all services (app + database)
docker-compose up --build
# Run in detached mode
docker-compose up -d --build
# Stop all services
docker-compose downThe app will be available at http://localhost:3000 by default.
This project uses Prisma as the ORM. The schema is defined in prisma/schema.prisma.
# Push schema changes to the database (development)
npx prisma db push
# Generate Prisma client after schema changes
npx prisma generate
# Open Prisma Studio (GUI for your database)
npx prisma studio
# Run migrations (production)
npx prisma migrate deploy
# Create a new migration
npx prisma migrate dev --name <migration_name>Note: Always run
npx prisma generateafter modifyingschema.prismato keep the type-safe client in sync.
# Run ESLint
npm run lint
# Auto-fix lint issues
npm run lint -- --fix# Check formatting
npm run format
# Auto-format with Prettier
npx prettier --write .Husky is configured to run lint and format checks automatically on every git commit via the .husky/pre-commit hook — keeping the codebase consistently clean without manual effort.
This project is licensed under the terms specified in the LICENSE file.