NestJS Best Practices & Optimization
This skill outlines the standards for creating scalable, manageable, and high-performance NestJS applications.
1. Architecture & Structure
Modularization (Scalability & Manageability)
- •Feature Modules: Organize code by domain feature (e.g.,
UsersModule,AuthModule,OrdersModule), not by technical layer (controllers, services). - •Shared Module: Create a
SharedModulefor reusable services/components (e.g., utility helpers) that don't depend on other modules. - •Core Module: Create a
CoreModulefor global singleton services (e.g., Interceptors, Filters, global pipes, Database connection config) that are imported only once inAppModule. - •Circular Dependencies: AVOID them. If you have them, your boundaries are wrong. Use
forwardRefonly as a last resort.
Directory Structure
code
src/ ├── common/ # Global generic code (filters, guards, interceptors, pipes, decorators) ├── config/ # Configuration files (validations, env loaders) ├── modules/ # Domain modules │ ├── users/ │ │ ├── dto/ # Data Transfer Objects │ │ ├── entities/ # Database Entities │ │ ├── users.controller.ts │ │ ├── users.service.ts │ │ └── users.module.ts ├── main.ts └── app.module.ts
2. Strong Typing & Validation (Readability & Reliability)
DTOs (Data Transfer Objects)
- •Always use DTOs for Controller inputs.
- •Validation: Use
class-validatorandclass-transformer. - •Strict Whitelisting: Enable
whitelist: truein global validation pipe to strip unexpected properties.
typescript
// main.ts
app.useGlobalPipes(new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true, // Automatically transform payloads to DTO instances
}));
Config Validation for Environment Variables
- •Do not use
process.envdirectly in services. - •Use
@nestjs/configwith a validation schema (Joi or class-validator) to ensure the app fails fast if env vars are missing.
3. Performance & Optimization
Database Interaction
- •Projections: Always select only the fields you need. Avoid
SELECT *. - •N+1 Problem: Use
relationscarefully or use QueryBuilder/DataLoaders. - •Indexes: Ensure database columns used in
WHERE,ORDER BY, andJOINare indexed.
Caching
- •Use
@nestjs/cache-managerfor expensive operations. - •Cache at the service level (method usage) or controller level (routes).
Compression
- •Enable Gzip compression in
main.ts:typescriptimport * as compression from 'compression'; app.use(compression());
4. Exception Handling (Clean Code)
- •Global Filters: Use detailed Global Exception Filters to normalize error responses.
- •Custom Exceptions: Create domain-specific exceptions extending
HttpException. - •Avoid Try-Catch in Controllers: Let the global filter handle standard errors, or catch in Service and re-throw a structured NestJS exception.
5. Security Practices
- •Helmet: Use
helmetmiddleware for setting security headers. - •Rate Limiting: Use
@nestjs/throttlerto prevent abuse. - •CORS: Configure CORS strictly; do not leave it open (
*) in production.
6. Testing (Manageability)
- •Unit Tests: Test Services in isolation by mocking Repositories/dependencies.
- •E2E Tests: Test Controllers and the full flow using Supertest.
- •Atomic Tests: Each test should verify a single behavior.
7. Readability Rules
- •Method Length: Methods should be short and focused (Single Responsibility Principle).
- •Naming:
- •
findAllUsers()vsget()(Descriptive) - •
UserDtovsUser(Suffixes for type clarification)
- •
- •Comments: Comment why, not what. Code should be self-documenting.