NestJS Framework with Drizzle ORM
Overview
Provides NestJS patterns with Drizzle ORM for building production-ready server-side applications. Covers CRUD modules, JWT authentication, database operations, migrations, testing, microservices, and GraphQL integration.
When to Use
-
Building REST APIs or GraphQL servers with NestJS
-
Setting up authentication and authorization with JWT
-
Implementing database operations with Drizzle ORM
-
Creating microservices with TCP/Redis transport
-
Writing unit and integration tests
-
Running database migrations with drizzle-kit
Instructions
-
Install dependencies: npm i drizzle-orm pg && npm i -D drizzle-kit tsx
-
Define schema: Create src/db/schema.ts with Drizzle table definitions
-
Create DatabaseService: Inject Drizzle client as a NestJS provider
-
Build CRUD module: Controller → Service → Repository pattern
-
Add validation: Use class-validator DTOs with ValidationPipe
-
Implement guards: Create JWT/Roles guards for route protection
-
Write tests: Use @nestjs/testing with mocked repositories
-
Run migrations: npx drizzle-kit generate → Verify SQL → npx drizzle-kit migrate
Examples
Complete CRUD Module with Drizzle
// src/db/schema.ts export const users = pgTable('users', { id: serial('id').primaryKey(), name: text('name').notNull(), email: text('email').notNull().unique(), createdAt: timestamp('created_at').defaultNow(), });
// src/users/dto/create-user.dto.ts export class CreateUserDto { @IsString() @IsNotEmpty() name: string; @IsEmail() email: string; }
// src/users/user.repository.ts @Injectable() export class UserRepository { constructor(private db: DatabaseService) {}
async findAll() { return this.db.database.select().from(users); }
async create(data: typeof users.$inferInsert) { return this.db.database.insert(users).values(data).returning(); } }
// src/users/users.service.ts @Injectable() export class UsersService { constructor(private repo: UserRepository) {}
async create(dto: CreateUserDto) { return this.repo.create(dto); } }
// src/users/users.controller.ts @Controller('users') export class UsersController { constructor(private service: UsersService) {}
@Post() create(@Body() dto: CreateUserDto) { return this.service.create(dto); } }
// src/users/users.module.ts @Module({ controllers: [UsersController], providers: [UsersService, UserRepository, DatabaseService], exports: [UsersService], }) export class UsersModule {}
JWT Authentication Guard
@Injectable() export class JwtAuthGuard implements CanActivate { constructor(private jwtService: JwtService) {}
canActivate(context: ExecutionContext) { const token = context.switchToHttp().getRequest() .headers.authorization?.split(' ')[1]; if (!token) return false; try { const decoded = this.jwtService.verify(token); context.switchToHttp().getRequest().user = decoded; return true; } catch { return false; } } }
Database Transactions
async transferFunds(fromId: number, toId: number, amount: number) {
return this.db.database.transaction(async (tx) => {
await tx.update(accounts)
.set({ balance: sql${accounts.balance} - ${amount} })
.where(eq(accounts.id, fromId));
await tx.update(accounts)
.set({ balance: sql${accounts.balance} + ${amount} })
.where(eq(accounts.id, toId));
});
}
Unit Testing with Mocks
describe('UsersService', () => { let service: UsersService; let repo: jest.Mocked<UserRepository>;
beforeEach(async () => { const module = await Test.createTestingModule({ providers: [ UsersService, { provide: UserRepository, useValue: { findAll: jest.fn(), create: jest.fn() } }, ], }).compile(); service = module.get(UsersService); repo = module.get(UserRepository); });
it('should create user', async () => { const dto = { name: 'John', email: 'john@example.com' }; repo.create.mockResolvedValue({ id: 1, ...dto, createdAt: new Date() }); expect(await service.create(dto)).toMatchObject(dto); }); });
Constraints and Warnings
-
DTOs required: Always use DTOs with class-validator, never accept raw objects
-
Transactions: Keep transactions short; avoid nested transactions
-
Guards order: JWT guard must run before Roles guard
-
Environment variables: Never hardcode DATABASE_URL or JWT_SECRET
-
Migrations: Run drizzle-kit generate after schema changes before deploying
-
Circular dependencies: Use forwardRef() carefully; prefer module restructuring
Best Practices
-
Validate all inputs with global ValidationPipe
-
Use transactions for multi-table operations
-
Document APIs with OpenAPI/Swagger decorators
References
Advanced patterns and detailed examples available in:
-
references/reference.md
-
Core patterns, guards, interceptors, microservices, GraphQL
-
references/drizzle-reference.md
-
Drizzle ORM installation, configuration, queries
-
references/workflow-optimization.md
-
Development workflows, parallel execution strategies