NestJS with Prisma Project Structure
NestJS integrated with Prisma ORM for type-safe database queries, auto-generated types, and seamless migrations.
Project Directory
myproject/
src/
Application source
main.ts
Bootstrap app
app.module.ts
Root module
prisma/
Prisma module
prisma.module.ts
Global module
prisma.service.ts
Extends PrismaClient
config/
configuration.ts
database.config.ts
common/
filters/
prisma-exception.filter.ts
Handle DB errors
interceptors/
transform.interceptor.ts
modules/
Feature modules
users/
users.module.ts
users.controller.ts
users.service.ts
Injects PrismaService
dto/
create-user.dto.ts
update-user.dto.ts
posts/
posts.module.ts
posts.controller.ts
posts.service.ts
dto/
create-post.dto.ts
prisma/
Prisma schema & migrations
schema.prisma
Database schema
seed.ts
Seed data script
migrations/
Migration history
.gitkeep
test/
app.e2e-spec.ts
jest-e2e.json
nest-cli.json
tsconfig.json
tsconfig.build.json
package.json
.env.example
DATABASE_URL here
.eslintrc.js
.prettierrc
.gitignore
README.md
Why This Structure?
Prisma generates TypeScript types from your schema—no manual entity definitions. The PrismaService wraps PrismaClient for proper NestJS lifecycle handling. A global PrismaModule makes it injectable anywhere.
Key Directories
- prisma/schema.prisma-Single source of truth for database models
- prisma/migrations/-Version-controlled database changes
- src/prisma/-NestJS module wrapping PrismaClient
- src/modules/*/-Features inject PrismaService directly
Getting Started
npm installcp .env.example .env(set DATABASE_URL)npx prisma migrate devnpx prisma db seednpm run start:dev
Best Practices
- Define relations in
schema.prisma, not service code - Use
@Transaction()decorator for multi-table writes - Run
prisma generatein CI after migrations - Keep
PrismaServicestateless—no business logic - Use Prisma's
selectandincludeto avoid over-fetching
Trade-offs
- No repository layer-Services use Prisma directly—simpler but less abstract
- Schema lock-in-Prisma schema syntax, not raw SQL migrations
- Query complexity-Complex joins may need raw SQL via
$queryRaw