Toolmingo
Guides19 min read

50 NestJS Interview Questions (With Answers)

Top NestJS interview questions with detailed answers and code examples — covering modules, controllers, providers, decorators, guards, interceptors, pipes, microservices, and testing.

NestJS is the dominant enterprise Node.js framework — built with TypeScript, heavily influenced by Angular, and designed for scalable server-side applications. Interviews test your understanding of its dependency injection system, decorators, module architecture, and Node.js runtime behaviour. This guide covers the 50 most common questions with concise answers and code examples.

Quick reference

Topic Most asked questions
Architecture Modules, controllers, providers, DI
Decorators @Module, @Controller, @Injectable, @Get/@Post
Pipes Validation, transformation, built-in pipes
Guards Auth, RBAC, JwtAuthGuard
Interceptors Logging, response transformation, caching
Exception filters HttpException, custom filters
Middleware Functional vs class-based
Database TypeORM, Prisma, repository pattern
Microservices TCP, Redis transport, events vs messages
Testing Unit tests, e2e tests, Test.createTestingModule

Architecture & Core Concepts

1. What is NestJS and why use it?

NestJS is a progressive Node.js framework built with TypeScript that provides an opinionated application architecture. It's inspired by Angular's module system and uses decorators for metadata.

Feature Express NestJS
Architecture Unopinionated Opinionated (modules/controllers/services)
TypeScript Optional First-class
DI system None Built-in IoC container
Decorators None Extensive
CLI None @nestjs/cli
Testing Manual setup Built-in Test module
// main.ts — NestJS bootstrap
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

2. Explain the NestJS module system.

Every NestJS app has at least one root module (AppModule). Modules are classes decorated with @Module() that group related controllers, providers, and imports.

@Module({
  imports: [TypeOrmModule.forFeature([User])],  // other modules
  controllers: [UsersController],                // route handlers
  providers: [UsersService, UsersRepository],   // injectable classes
  exports: [UsersService],                       // expose to other modules
})
export class UsersModule {}
Property Purpose
imports Other modules whose exports this module needs
controllers Route handler classes
providers Services, repositories, guards, pipes — injected via DI
exports Subset of providers available to importing modules

3. What is Dependency Injection in NestJS?

NestJS uses an IoC (Inversion of Control) container. When a class has @Injectable(), NestJS manages its lifecycle and automatically injects it where needed.

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private readonly usersRepo: Repository<User>,
    private readonly mailerService: MailerService,  // injected automatically
  ) {}
}

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}  // DI
}

Benefits: testability (swap real services for mocks), loose coupling, single instance per module by default (singleton scope).


4. What are the different provider scopes in NestJS?

Scope Behaviour Use case
DEFAULT (Singleton) One instance per module; shared across all requests Stateless services
REQUEST New instance per request; destroyed after response Request-specific state, logger with request ID
TRANSIENT New instance each time it's injected Stateless but unshared
@Injectable({ scope: Scope.REQUEST })
export class RequestContextService {
  private requestId = Math.random();
}

5. What is the difference between @Module, @Controller, and @Injectable?

Decorator Applied to Purpose
@Module() Class Declares a module — organises the application
@Controller() Class Declares a route handler — maps HTTP requests to methods
@Injectable() Class Marks a class as a provider — eligible for DI

Controllers & Routing

6. How do you handle route parameters, query params, and request body?

@Controller('users')
export class UsersController {
  @Get(':id')
  findOne(
    @Param('id', ParseIntPipe) id: number,   // route param
    @Query('include') include: string,         // query param
  ) { ... }

  @Post()
  create(@Body() createUserDto: CreateUserDto) { ... }  // request body

  @Put(':id')
  update(
    @Param('id') id: string,
    @Body() dto: UpdateUserDto,
  ) { ... }

  @Delete(':id')
  remove(@Param('id') id: string) { ... }
}

7. What HTTP method decorators does NestJS provide?

Decorator HTTP method
@Get() GET
@Post() POST
@Put() PUT
@Patch() PATCH
@Delete() DELETE
@Options() OPTIONS
@Head() HEAD
@All() All methods

8. How do you return different HTTP status codes?

@Post()
@HttpCode(201)
create(@Body() dto: CreateUserDto) { ... }

// Or use @Res() for full control (not recommended — breaks interceptors)
@Get()
findAll(@Res() res: Response) {
  res.status(200).json([]);
}

// Throw exceptions for errors
@Get(':id')
async findOne(@Param('id') id: string) {
  const user = await this.usersService.findOne(+id);
  if (!user) throw new NotFoundException(`User #${id} not found`);
  return user;
}

9. How do you use route prefixes and versioning?

// Global prefix
app.setGlobalPrefix('api');

// Module-level prefix
@Controller('users')  // → /api/users

// Versioning
app.enableVersioning({ type: VersioningType.URI });

@Controller({ path: 'users', version: '1' })  // → /api/v1/users

Pipes

10. What are pipes and what are they used for?

Pipes operate on the arguments being processed by a route handler. They do two things: transformation (parse string to int) and validation (throw if DTO is invalid).

// Built-in pipes
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) { ... }

// ValidationPipe with class-validator
@Post()
create(@Body(ValidationPipe) dto: CreateUserDto) { ... }

11. What built-in pipes does NestJS provide?

Pipe Purpose
ValidationPipe Validates DTOs with class-validator
ParseIntPipe Converts string to integer
ParseFloatPipe Converts string to float
ParseBoolPipe Converts "true"/"false" to boolean
ParseArrayPipe Parses array from query string
ParseUUIDPipe Validates UUID format
ParseEnumPipe Validates enum membership
DefaultValuePipe Provides a fallback default value

12. How do you use ValidationPipe with DTOs?

// DTO with class-validator decorators
import { IsEmail, IsString, MinLength, IsOptional } from 'class-validator';

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(8)
  password: string;

  @IsString()
  @IsOptional()
  name?: string;
}

// Enable globally (recommended)
app.useGlobalPipes(new ValidationPipe({
  whitelist: true,       // strip unknown properties
  forbidNonWhitelisted: true,  // throw on unknown properties
  transform: true,       // auto-transform to DTO class instance
}));

13. How do you create a custom pipe?

import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';

@Injectable()
export class PositiveIntPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    const val = parseInt(value, 10);
    if (isNaN(val) || val <= 0) {
      throw new BadRequestException('Value must be a positive integer');
    }
    return val;
  }
}

// Usage
@Get(':count')
list(@Param('count', PositiveIntPipe) count: number) { ... }

Guards

14. What are guards and how do they work?

Guards determine whether a request should be handled by the route handler. They implement CanActivate and execute after middleware but before interceptors and pipes.

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const token = request.headers.authorization?.split(' ')[1];
    if (!token) throw new UnauthorizedException();
    try {
      request.user = this.jwtService.verify(token);
      return true;
    } catch {
      throw new UnauthorizedException();
    }
  }
}

15. How do you implement role-based access control (RBAC)?

// Custom decorator
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);

// Guard
@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    if (!roles) return true;  // no roles required
    const { user } = context.switchToHttp().getRequest();
    return roles.some(role => user.roles?.includes(role));
  }
}

// Usage
@Get('admin')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
adminOnly() { ... }

16. How do you apply guards globally, at controller level, or at method level?

// Global
app.useGlobalGuards(new JwtAuthGuard());

// Controller level
@Controller('admin')
@UseGuards(JwtAuthGuard, RolesGuard)
export class AdminController { ... }

// Method level
@Get('secret')
@UseGuards(JwtAuthGuard)
getSecret() { ... }

Interceptors

17. What are interceptors in NestJS?

Interceptors wrap the execution of route handlers. They can:

  • Transform the response
  • Add extra logic before/after the handler
  • Override the response entirely
  • Handle errors
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const start = Date.now();
    const req = context.switchToHttp().getRequest();
    console.log(`→ ${req.method} ${req.url}`);
    return next.handle().pipe(
      tap(() => console.log(`← ${Date.now() - start}ms`)),
    );
  }
}

18. How do you create a response transformation interceptor?

// Wrap all responses in { data: ... }
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, { data: T }> {
  intercept(context: ExecutionContext, next: CallHandler): Observable<{ data: T }> {
    return next.handle().pipe(
      map(data => ({ data })),
    );
  }
}

// Global registration
app.useGlobalInterceptors(new TransformInterceptor());

19. What is the execution order of NestJS request lifecycle?

Incoming Request
  → Middleware (global → module)
  → Guards (global → controller → method)
  → Interceptors (global → controller → method) — before
  → Pipes (global → controller → method → parameter)
  → Route Handler
  ← Interceptors (method → controller → global) — after
  ← Exception Filters (if error thrown)
  ← Response

Exception Filters

20. What built-in HTTP exceptions does NestJS provide?

Exception Status Code
BadRequestException 400
UnauthorizedException 401
ForbiddenException 403
NotFoundException 404
ConflictException 409
UnprocessableEntityException 422
InternalServerErrorException 500
HttpException (base) Any

21. How do you create a custom exception filter?

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
      message: exception.message,
    });
  }
}

// Apply globally
app.useGlobalFilters(new HttpExceptionFilter());

Middleware

22. How is NestJS middleware different from Express middleware?

NestJS middleware is equivalent to Express middleware — it's called before route handlers and has access to req, res, and next. However, it cannot access the execution context (unlike Guards/Interceptors).

// Functional middleware
export function logger(req: Request, res: Response, next: NextFunction) {
  console.log(`${req.method} ${req.url}`);
  next();
}

// Class-based middleware
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(`${req.method} ${req.url}`);
    next();
  }
}

// Apply in module
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes({ path: 'users', method: RequestMethod.GET });
  }
}

23. When should you use middleware vs guards vs interceptors?

Concern Use
Request logging Middleware or Interceptor
Authentication (parse token) Middleware
Authorization (can user access?) Guard
Response transformation Interceptor
Request/response logging with timing Interceptor
CORS, body parsing Middleware
Caching responses Interceptor
Business-rule access control Guard

Database Integration

24. How do you integrate TypeORM with NestJS?

// app.module.ts
@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DB_HOST,
      port: +process.env.DB_PORT,
      username: process.env.DB_USER,
      password: process.env.DB_PASS,
      database: process.env.DB_NAME,
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: false,  // never true in production
    }),
    TypeOrmModule.forFeature([User]),  // per-module
  ],
})
export class AppModule {}

// Entity
@Entity('users')
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @CreateDateColumn()
  createdAt: Date;
}

// Service injection
@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private usersRepo: Repository<User>,
  ) {}

  findAll() { return this.usersRepo.find(); }
  findOne(id: number) { return this.usersRepo.findOneBy({ id }); }
}

25. How do you use Prisma with NestJS?

// prisma.service.ts
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }
}

// Module
@Module({
  providers: [PrismaService, UsersService],
  exports: [PrismaService],
})
export class DatabaseModule {}

// Service
@Injectable()
export class UsersService {
  constructor(private prisma: PrismaService) {}

  findAll() {
    return this.prisma.user.findMany();
  }

  create(data: Prisma.UserCreateInput) {
    return this.prisma.user.create({ data });
  }
}

26. What is the Repository pattern in NestJS with TypeORM?

The Repository pattern wraps the ORM to keep business logic clean. NestJS TypeORM integration provides Repository<Entity> out of the box, but you can extend it for custom queries.

@Injectable()
export class UsersRepository {
  constructor(
    @InjectRepository(User)
    private readonly repo: Repository<User>,
  ) {}

  async findByEmail(email: string): Promise<User | null> {
    return this.repo.findOne({ where: { email } });
  }

  async findActiveUsers(): Promise<User[]> {
    return this.repo.createQueryBuilder('user')
      .where('user.isActive = :active', { active: true })
      .orderBy('user.createdAt', 'DESC')
      .getMany();
  }
}

Authentication & Security

27. How do you implement JWT authentication in NestJS?

// auth.module.ts
@Module({
  imports: [
    JwtModule.register({
      secret: process.env.JWT_SECRET,
      signOptions: { expiresIn: '7d' },
    }),
    UsersModule,
  ],
  providers: [AuthService, JwtStrategy],
  controllers: [AuthController],
})
export class AuthModule {}

// jwt.strategy.ts
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: process.env.JWT_SECRET,
    });
  }

  async validate(payload: { sub: number; email: string }) {
    return { userId: payload.sub, email: payload.email };
  }
}

// auth.service.ts
@Injectable()
export class AuthService {
  constructor(
    private usersService: UsersService,
    private jwtService: JwtService,
  ) {}

  async login(email: string, password: string) {
    const user = await this.usersService.findByEmail(email);
    if (!user || !bcrypt.compareSync(password, user.password)) {
      throw new UnauthorizedException('Invalid credentials');
    }
    return {
      access_token: this.jwtService.sign({ sub: user.id, email: user.email }),
    };
  }
}

// Protect route
@Get('profile')
@UseGuards(AuthGuard('jwt'))
getProfile(@Request() req) {
  return req.user;
}

28. How do you protect routes using @nestjs/passport?

// Built-in guard
@UseGuards(AuthGuard('jwt'))

// Custom guard (recommended for reuse)
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  handleRequest(err: any, user: any) {
    if (err || !user) throw err || new UnauthorizedException();
    return user;
  }
}

// Usage
@Get('me')
@UseGuards(JwtAuthGuard)
getMe(@Request() req) { return req.user; }

Configuration

29. How do you manage configuration/environment variables in NestJS?

// app.module.ts
@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,         // no need to import in every module
      envFilePath: '.env',
      validationSchema: Joi.object({
        PORT: Joi.number().default(3000),
        DATABASE_URL: Joi.string().required(),
        JWT_SECRET: Joi.string().required(),
      }),
    }),
  ],
})
export class AppModule {}

// Inject in service
@Injectable()
export class UsersService {
  constructor(private config: ConfigService) {}

  getDbUrl() { return this.config.get<string>('DATABASE_URL'); }
}

30. What is forRoot vs forFeature in NestJS?

Method Usage
forRoot() Configure once at root — establishes the connection/global config
forFeature() Register feature-level resources (entities, stores) in a specific module
// Root — database connection
TypeOrmModule.forRoot({ ... })

// Feature — entity repositories for UsersModule
TypeOrmModule.forFeature([User, UserProfile])

Custom Decorators

31. How do you create custom parameter decorators?

// Extract current user from request
export const CurrentUser = createParamDecorator(
  (data: string | undefined, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const user = request.user;
    return data ? user?.[data] : user;
  },
);

// Usage
@Get('profile')
@UseGuards(JwtAuthGuard)
getProfile(@CurrentUser() user: User) { return user; }

@Get('email')
@UseGuards(JwtAuthGuard)
getEmail(@CurrentUser('email') email: string) { return email; }

32. How do you create custom class decorators?

// Compose multiple decorators
export function Auth(...roles: string[]) {
  return applyDecorators(
    SetMetadata('roles', roles),
    UseGuards(JwtAuthGuard, RolesGuard),
    ApiBearerAuth(),         // Swagger
    ApiUnauthorizedResponse({ description: 'Unauthorized' }),
  );
}

// Usage — clean and reusable
@Get('admin')
@Auth('admin')
adminPanel() { ... }

Microservices

33. How does NestJS support microservices?

NestJS has a built-in @nestjs/microservices package with multiple transport layers.

// TCP microservice
const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
  transport: Transport.TCP,
  options: { port: 3001 },
});
await app.listen();

// Message handler in microservice
@MessagePattern('get_user')
getUser(@Payload() data: { id: number }) {
  return this.usersService.findOne(data.id);
}

// Client (calling microservice)
@Injectable()
export class ApiGatewayService {
  private client = ClientProxyFactory.create({
    transport: Transport.TCP,
    options: { port: 3001 },
  });

  getUser(id: number) {
    return this.client.send('get_user', { id }).toPromise();
  }
}

34. What is the difference between @MessagePattern and @EventPattern?

Decorator Communication Response
@MessagePattern Request-response Returns a value to the caller
@EventPattern Fire-and-forget No return value; async notification
// Request-response
@MessagePattern('calculate_tax')
calculate(@Payload() data: TaxData): number {
  return data.amount * 0.2;
}

// Event (one-way)
@EventPattern('user.created')
handleUserCreated(@Payload() data: UserCreatedEvent) {
  this.emailService.sendWelcome(data.email);
}

35. What transports does NestJS microservices support?

Transport Use case
TCP Simple inter-service communication
Redis Pub/sub with fan-out
NATS Cloud-native messaging
Kafka High-throughput event streaming
RabbitMQ (AMQP) Reliable queuing
gRPC High-performance typed contracts
MQTT IoT/lightweight messaging

WebSockets

36. How do you implement WebSockets in NestJS?

@WebSocketGateway({
  cors: { origin: '*' },
  namespace: '/chat',
})
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer() server: Server;

  handleConnection(client: Socket) {
    console.log(`Client connected: ${client.id}`);
  }

  handleDisconnect(client: Socket) {
    console.log(`Client disconnected: ${client.id}`);
  }

  @SubscribeMessage('message')
  handleMessage(client: Socket, payload: { room: string; text: string }) {
    this.server.to(payload.room).emit('message', {
      sender: client.id,
      text: payload.text,
    });
  }
}

Testing

37. How do you write unit tests in NestJS?

// users.service.spec.ts
describe('UsersService', () => {
  let service: UsersService;
  let repo: jest.Mocked<Repository<User>>;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        UsersService,
        {
          provide: getRepositoryToken(User),
          useValue: {
            find: jest.fn(),
            findOne: jest.fn(),
            save: jest.fn(),
            create: jest.fn(),
          },
        },
      ],
    }).compile();

    service = module.get<UsersService>(UsersService);
    repo = module.get(getRepositoryToken(User));
  });

  it('should return all users', async () => {
    const users = [{ id: 1, email: 'test@test.com' }] as User[];
    repo.find.mockResolvedValue(users);

    const result = await service.findAll();
    expect(result).toEqual(users);
    expect(repo.find).toHaveBeenCalledTimes(1);
  });
});

38. How do you write e2e tests in NestJS?

// app.e2e-spec.ts
describe('UsersController (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = module.createNestApplication();
    app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
    await app.init();
  });

  afterAll(() => app.close());

  it('GET /users — returns array', () => {
    return request(app.getHttpServer())
      .get('/users')
      .expect(200)
      .expect(res => expect(Array.isArray(res.body)).toBe(true));
  });

  it('POST /users — validates body', () => {
    return request(app.getHttpServer())
      .post('/users')
      .send({ email: 'not-an-email' })
      .expect(400);
  });
});

39. How do you mock providers in NestJS tests?

// Using useValue
{ provide: UsersService, useValue: { findAll: jest.fn().mockResolvedValue([]) } }

// Using useFactory
{ provide: ConfigService, useFactory: () => ({ get: jest.fn().mockReturnValue('secret') }) }

// Using jest.spyOn after getting the real service
const service = module.get<UsersService>(UsersService);
jest.spyOn(service, 'findAll').mockResolvedValue([]);

Performance & Advanced

40. How do you enable caching in NestJS?

// Module setup
@Module({
  imports: [
    CacheModule.register({
      store: redisStore,
      host: 'localhost',
      port: 6379,
      ttl: 60,  // seconds
    }),
  ],
})

// Interceptor-based (automatic)
@UseInterceptors(CacheInterceptor)
@Controller('products')
export class ProductsController {
  @Get()
  @CacheTTL(30)
  findAll() { ... }
}

// Manual cache
@Injectable()
export class ProductsService {
  constructor(@Inject(CACHE_MANAGER) private cache: Cache) {}

  async findFeatured() {
    const cached = await this.cache.get('featured');
    if (cached) return cached;
    const data = await this.fetchFeatured();
    await this.cache.set('featured', data, 60);
    return data;
  }
}

41. What is lazy module loading and when do you use it?

Lazy loading delays the instantiation of a module until it's actually needed — useful in serverless environments or when certain features are rarely used.

@Injectable()
export class LazyLoaderService {
  constructor(private readonly lazyModuleLoader: LazyModuleLoader) {}

  async loadHeavyModule() {
    const { HeavyModule } = await import('./heavy/heavy.module');
    const moduleRef = await this.lazyModuleLoader.load(() => HeavyModule);
    return moduleRef.get(HeavyService);
  }
}

42. How do you handle file uploads in NestJS?

// Using Multer
@Post('upload')
@UseInterceptors(FileInterceptor('file', {
  storage: diskStorage({
    destination: './uploads',
    filename: (req, file, cb) => cb(null, `${Date.now()}-${file.originalname}`),
  }),
  fileFilter: (req, file, cb) => {
    const allowed = ['image/jpeg', 'image/png', 'image/webp'];
    cb(null, allowed.includes(file.mimetype));
  },
  limits: { fileSize: 5 * 1024 * 1024 },  // 5MB
}))
uploadFile(@UploadedFile() file: Express.Multer.File) {
  return { filename: file.filename };
}

43. How do you implement task scheduling in NestJS?

// Install: @nestjs/schedule
@Module({ imports: [ScheduleModule.forRoot()] })

@Injectable()
export class TasksService {
  // Runs every day at midnight
  @Cron('0 0 * * *')
  cleanupExpiredSessions() { ... }

  // Runs every 30 seconds
  @Interval(30_000)
  healthCheck() { ... }

  // Runs once after 10 seconds
  @Timeout(10_000)
  initialSync() { ... }
}

44. What is ExecutionContext and Reflector?

ExecutionContext provides a context-agnostic way to access request details (works for HTTP, WebSockets, and microservices). Reflector reads metadata set by SetMetadata.

// In a guard or interceptor
canActivate(context: ExecutionContext): boolean {
  // HTTP
  const req = context.switchToHttp().getRequest();
  // WebSocket
  const client = context.switchToWs().getClient();
  // Microservice
  const data = context.switchToRpc().getData();

  // Read metadata
  const roles = this.reflector.get<string[]>('roles', context.getHandler());
  const classRoles = this.reflector.get<string[]>('roles', context.getClass());
  // Merge both (method overrides class)
  const allRoles = this.reflector.getAllAndMerge('roles', [
    context.getHandler(),
    context.getClass(),
  ]);
}

45. How do you use @nestjs/swagger to document your API?

// main.ts
const config = new DocumentBuilder()
  .setTitle('Users API')
  .setDescription('User management endpoints')
  .setVersion('1.0')
  .addBearerAuth()
  .build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api/docs', app, document);

// DTO
export class CreateUserDto {
  @ApiProperty({ example: 'user@example.com' })
  @IsEmail()
  email: string;

  @ApiProperty({ example: 'StrongPassword1!' })
  @IsString()
  @MinLength(8)
  password: string;
}

// Controller
@ApiTags('users')
@ApiBearerAuth()
@Controller('users')
export class UsersController {
  @ApiOperation({ summary: 'Get all users' })
  @ApiResponse({ status: 200, type: [UserDto] })
  @Get()
  findAll() { ... }
}

46. How does forRootAsync work for dynamic configuration?

Use forRootAsync when the config values come from asynchronous sources like ConfigService or secrets managers.

TypeOrmModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: (config: ConfigService) => ({
    type: 'postgres',
    url: config.get<string>('DATABASE_URL'),
    entities: [__dirname + '/**/*.entity{.ts,.js}'],
    synchronize: false,
  }),
  inject: [ConfigService],
})

Common Mistakes

47–50. Anti-patterns to avoid

Anti-pattern Problem Fix
Circular dependency UsersModule ↔ AuthModule causes Nest DI to fail Use forwardRef(() => Module) or restructure
Injecting Repository directly in controller Bypasses service layer Always inject through service
Using @Res() everywhere Breaks interceptors and exception filters Use return values; use @Res() only when truly needed
Skipping whitelist: true in ValidationPipe Allows extra properties through, potential mass-assignment Always use whitelist: true, forbidNonWhitelisted: true
synchronize: true in production TypeORM Auto-drops and recreates columns, causes data loss Set to false, use migrations
Not using OnModuleDestroy Connections leak on app shutdown Implement OnModuleDestroy to clean up resources
Global state in singleton services REQUEST-scoped side effects bleed between requests Use Scope.REQUEST or pass context explicitly
Blocking event loop with sync heavy work Freezes all requests Offload to worker threads or queue

NestJS vs Express vs Fastify

Feature NestJS Express Fastify
Architecture Opinionated (modules/DI) Unopinionated Unopinionated
TypeScript First-class Optional Optional
DI container Built-in None None
Performance Slightly slower (DI overhead) Fast Fastest
Learning curve Steep Gentle Gentle
Testing Excellent (Test module) Manual setup Manual setup
CLI Yes (nest generate) No No
Microservices Built-in None None
WebSockets Built-in (Gateways) Manual Manual
Documentation Excellent Good Good
Use case Enterprise/large teams Simple APIs, full control Performance-critical

FAQ

Q: Should I use NestJS or Express for a new project?

Choose NestJS for enterprise applications, large teams, or projects that will grow significantly. The opinionated structure, built-in DI, and testing utilities pay off at scale. Choose Express for simple microservices, quick prototypes, or when you want full control over the stack.

Q: Does NestJS support both REST and GraphQL?

Yes. Install @nestjs/graphql and @apollo/server (or Mercurius for Fastify). NestJS provides a code-first (TypeScript decorators) and schema-first (SDL) approach.

Q: How does NestJS handle circular dependencies?

Use forwardRef:

@Module({
  imports: [forwardRef(() => AuthModule)],
})
export class UsersModule {}

Or restructure to extract shared logic into a third module both can import without a cycle.

Q: Can NestJS run on Fastify instead of Express?

Yes:

const app = await NestFactory.create<NestFastifyApplication>(
  AppModule,
  new FastifyAdapter(),
);

Fastify is ~20-30% faster but has a slightly different ecosystem (some Express middleware won't work directly).

Q: How do you handle database transactions in NestJS with TypeORM?

async createWithProfile(dto: CreateUserDto) {
  return this.dataSource.transaction(async manager => {
    const user = manager.create(User, dto);
    await manager.save(user);
    const profile = manager.create(UserProfile, { userId: user.id });
    await manager.save(profile);
    return user;
  });
}

Q: What's the difference between useClass, useValue, and useFactory for providers?

Option Use when
useClass Standard class instantiation via DI (default)
useValue Provide a pre-built object or primitive (config object, mock)
useFactory Async or dynamic provider creation (depends on other providers)
useExisting Alias one provider to another
{ provide: APP_GUARD, useClass: JwtAuthGuard }
{ provide: 'CONFIG', useValue: { timeout: 5000 } }
{ provide: DatabaseService, useFactory: async (config) => { ... }, inject: [ConfigService] }

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools