Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

NestJS User Guide

Generated May 2026 from nestjs/nest at 4b6420b

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Quick Start

NestJS is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications. Built with TypeScript and inspired by Angular's architecture, it provides an opinionated application structure based on modules, controllers, and providers with a powerful dependency injection system.

Key features:

  • TypeScript-first with full JavaScript compatibility
  • Modular architecture with dependency injection
  • Platform-agnostic HTTP layer (Express or Fastify)
  • Built-in support for WebSockets, microservices, and GraphQL
  • Extensive decorator-based routing and validation
  • Lifecycle hooks for application and module events
  • First-class testing support with @nestjs/testing
  • REPL mode for interactive debugging

Prerequisites: Node.js >= 20

npm i -g @nestjs/cli
nest new my-project
cd my-project
npm run start
[Nest] 12345  - 05/07/2026, 10:00:00 AM     LOG [NestFactory] Starting Nest application...
[Nest] 12345  - 05/07/2026, 10:00:00 AM     LOG [NestApplication] Nest application successfully started

Tip

Use npm run start:dev for watch mode during development. The @nestjs/cli provides nest start --watch which automatically recompiles on file changes.

What to try next:

  • Add a new controller: see Core Usage below
  • Connect a database: see Common Tasks
  • Add validation: see the Pipes section
  • See the Admin Guide for full architecture and configuration reference

2. Installation

System Requirements

Requirement Version
Node.js >= 20
npm >= 9 (ships with Node 20)
TypeScript 5.x (included)

Installation Methods

CLI (Recommended)

npm i -g @nestjs/cli
nest new my-project

Manual Setup

mkdir my-project && cd my-project
npm init -y
npm i @nestjs/core @nestjs/common @nestjs/platform-express reflect-metadata rxjs
npm i -D @nestjs/cli typescript @types/node

Fastify Platform

npm i @nestjs/core @nestjs/common @nestjs/platform-fastify reflect-metadata rxjs

Important

The reflect-metadata package is required for decorator metadata reflection. It must be imported once in your application entry point (main.ts).

Core Packages

Package Purpose
@nestjs/core Framework core (DI container, lifecycle, routing)
@nestjs/common Decorators, pipes, guards, interceptors, exceptions
@nestjs/platform-express Express HTTP adapter (default)
@nestjs/platform-fastify Fastify HTTP adapter (alternative)
@nestjs/testing Testing utilities
@nestjs/microservices Microservice transports (TCP, Redis, NATS, MQTT, RMQ, Kafka, gRPC)
@nestjs/websockets WebSocket gateway support
@nestjs/platform-socket.io Socket.IO adapter
@nestjs/platform-ws WS adapter

Post-Install Verification

nest --version
11.0.0
npm run start
[Nest] 12345  - LOG [NestFactory] Starting Nest application...
[Nest] 12345  - LOG [RoutesResolver] AppController {/}: +2ms
[Nest] 12345  - LOG [RouterExplorer] Mapped {/, GET} route +1ms
[Nest] 12345  - LOG [NestApplication] Nest application successfully started +1ms

Install Troubleshooting

Error: Cannot find module 'reflect-metadata'

Cause: Missing required dependency.

Solution:

  1. Install reflect-metadata:
    npm i reflect-metadata
    
  2. Ensure it is imported at the top of main.ts:
    import 'reflect-metadata';
    

Error: Experimental support for decorators is a feature that is subject to change

Cause: TypeScript decorator support not enabled.

Solution: Add to tsconfig.json:

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  }
}

Error: nest: command not found

Cause: NestJS CLI not installed globally or not in PATH.

Solution:

npm i -g @nestjs/cli

Or use npx:

npx @nestjs/cli new my-project

3. Configuration

NestJS applications are configured programmatically through the main.ts bootstrap function and module imports. There is no central configuration file — settings are applied via method calls on the application instance and decorator metadata.

Bootstrap Configuration

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: ['error', 'warn', 'log'],  // Control log levels
    cors: true,                         // Enable CORS
    abortOnError: false,                // Don't abort on init errors
  });

  app.setGlobalPrefix('api');           // Prefix all routes
  app.enableVersioning({ type: VersioningType.URI }); // API versioning

  await app.listen(3000);
}
bootstrap();

Common Configuration Options

Option Type Default Description
logger LogLevel[] | LoggerService | false All levels Log output control
cors boolean | CorsOptions false Cross-origin resource sharing
abortOnError boolean true Abort on initialization errors
bodyParser boolean true Enable built-in body parsing
rawBody boolean false Expose raw request body
preview boolean false Preview mode (no listeners)
forceCloseConnections boolean false Force-close HTTP connections on shutdown

Environment Variables

Variable Purpose
NO_COLOR Disables colored log output when set
NEST_DEBUG Enables debug-level DI container logging when set

Tip

For complex configuration, use the dynamic modules pattern with ConfigModule from @nestjs/config (separate package). See the Dynamic Modules section in Common Tasks for the pattern used to build configurable modules.

See the Admin Guide for the full configuration reference including all versioning types, global prefix options, and platform-specific adapter settings.

4. Core Usage

Modules

Every NestJS application has at least one module — the root AppModule. Modules organize the application into cohesive blocks of functionality.

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService],  // Make available to importing modules
})
export class CatsModule {}

@Module() options:

Property Description
imports Modules whose exported providers are needed in this module
controllers Controllers that handle incoming requests
providers Services, repositories, and other injectables
exports Providers available to modules that import this module

Note

Use @Global() on a module to make its exports available everywhere without explicit imports. Use sparingly — global modules reduce encapsulation.

Controllers

Controllers handle incoming requests and return responses. Each controller method is mapped to a route via HTTP method decorators.

import {
  Controller, Get, Post, Put, Delete, Patch,
  Body, Param, Query, Headers, Ip,
  HttpCode, Header, Redirect,
} from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';

@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Post()
  @HttpCode(201)
  create(@Body() createCatDto: CreateCatDto) {
    return this.catsService.create(createCatDto);
  }

  @Get()
  findAll(@Query('limit') limit: number) {
    return this.catsService.findAll(limit);
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.catsService.findOne(id);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() updateCatDto: any) {
    return this.catsService.update(id, updateCatDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.catsService.remove(id);
  }
}

HTTP method decorators:

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

Parameter decorators:

Decorator Maps to
@Body(key?) req.body / req.body[key]
@Query(key?) req.query / req.query[key]
@Param(key?) req.params / req.params[key]
@Headers(name?) req.headers / req.headers[name]
@Req() Full request object
@Res() Full response object
@Session() req.session
@Ip() req.ip
@HostParam() req.hosts
@RawBody() Raw request body buffer

Warning

Using @Res() puts the response in library-specific mode — NestJS will not automatically serialize the return value. You must call res.json() or res.send() manually, or use @Res({ passthrough: true }) to let NestJS handle the response while still accessing the response object.

Providers (Services)

Providers are classes annotated with @Injectable() that can be injected through the constructor. They encapsulate business logic.

import { Injectable } from '@nestjs/common';

@Injectable()
export class CatsService {
  private readonly cats: Cat[] = [];

  create(cat: CreateCatDto): Cat {
    this.cats.push(cat);
    return cat;
  }

  findAll(limit?: number): Cat[] {
    return limit ? this.cats.slice(0, limit) : this.cats;
  }

  findOne(id: string): Cat {
    return this.cats.find(cat => cat.id === id);
  }
}

Custom providers allow more control over instantiation:

@Module({
  providers: [
    { provide: CatsService, useClass: CatsService },       // Standard
    { provide: 'CONFIG', useValue: { debug: true } },       // Value
    { provide: 'ASYNC_CONFIG', useFactory: async () => {    // Factory
        const config = await loadConfig();
        return config;
      },
      inject: [ConfigService],  // Dependencies for factory
    },
    { provide: 'ALIAS', useExisting: CatsService },         // Alias
  ],
})

Middleware

Middleware functions execute before route handlers. They have access to the request and response objects and the next() function.

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

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

Apply middleware in the module:

import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';

@Module({ controllers: [CatsController] })
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes(CatsController);
  }
}

Pipes

Pipes transform or validate input data. NestJS includes several built-in pipes.

Built-in pipes:

Pipe Purpose
ValidationPipe Validates DTOs using class-validator
ParseIntPipe Parses string to integer
ParseFloatPipe Parses string to float
ParseBoolPipe Parses string to boolean
ParseArrayPipe Parses string to array
ParseUUIDPipe Validates and parses UUID strings
ParseEnumPipe Validates enum values
DefaultValuePipe Provides a default value when parameter is undefined
ParseFilePipe Validates file uploads
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
  return this.catsService.findOne(id);
}

Tip

Apply ValidationPipe globally for automatic DTO validation across all routes:

app.useGlobalPipes(new ValidationPipe({
  whitelist: true,        // Strip non-decorated properties
  transform: true,        // Auto-transform payloads to DTO instances
  forbidNonWhitelisted: true,  // Throw on extra properties
}));

Guards

Guards determine whether a request should be handled by the route handler. They implement the CanActivate interface.

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    return !!request.headers.authorization;
  }
}

Apply with @UseGuards():

@Controller('cats')
@UseGuards(AuthGuard)
export class CatsController {}

Or globally:

app.useGlobalGuards(new AuthGuard());

Interceptors

Interceptors add extra logic before/after method execution, transform results, handle errors, or extend behavior using RxJS observables.

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      map(data => ({ data, timestamp: new Date().toISOString() })),
    );
  }
}

Apply with @UseInterceptors():

@UseInterceptors(TransformInterceptor)
@Get()
findAll() {
  return this.catsService.findAll();
}

Exception Filters

Exception filters catch unhandled exceptions and format error responses.

import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';

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

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

Built-in HTTP exceptions:

Exception Status Code
BadRequestException 400
UnauthorizedException 401
ForbiddenException 403
NotFoundException 404
MethodNotAllowedException 405
NotAcceptableException 406
RequestTimeoutException 408
ConflictException 409
GoneException 410
PayloadTooLargeException 413
UnsupportedMediaTypeException 415
UnprocessableEntityException 422
InternalServerErrorException 500
NotImplementedException 501
BadGatewayException 502
ServiceUnavailableException 503
GatewayTimeoutException 504
ImATeapotException 418
PreconditionFailedException 412
HttpVersionNotSupportedException 505
throw new NotFoundException(`Cat #${id} not found`);

Execution Order

NestJS processes requests through the following pipeline:

Request → Middleware → Guards → Interceptors (before) → Pipes → Route Handler
       → Interceptors (after) → Exception Filters (on error) → Response

Important

The execution order matters for debugging. Guards run after middleware but before pipes. If a guard rejects the request, pipes and the route handler never execute.

5. Common Tasks

Set Up a Database with TypeORM

Goal: Connect a NestJS application to a SQL database using TypeORM.

Prerequisites: @nestjs/typeorm, typeorm, database driver (e.g., mysql2, pg)

Steps:

  1. Install dependencies:

    npm i @nestjs/typeorm typeorm mysql2
    
  2. Configure in AppModule:

    import { TypeOrmModule } from '@nestjs/typeorm';
    
    @Module({
      imports: [
        TypeOrmModule.forRoot({
          type: 'mysql',
          host: 'localhost',
          port: 3306,
          username: 'root',
          password: 'root',
          database: 'test',
          entities: [Photo],
          synchronize: true,  // Disable in production
        }),
        TypeOrmModule.forFeature([Photo]),
      ],
    })
    export class AppModule {}
    
  3. Create an entity:

    import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
    
    @Entity()
    export class Photo {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column()
      name: string;
    }
    
  4. Inject the repository:

    @Injectable()
    export class PhotoService {
      constructor(
        @InjectRepository(Photo)
        private readonly photoRepo: Repository<Photo>,
      ) {}
    }
    

Warning

Never use synchronize: true in production — it can cause data loss. Use TypeORM migrations instead.

Set Up a Database with Mongoose

Goal: Connect to MongoDB using Mongoose.

Prerequisites: @nestjs/mongoose, mongoose

npm i @nestjs/mongoose mongoose
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://localhost/test'),
    MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }]),
  ],
})
export class AppModule {}

JWT Authentication

Goal: Add JWT-based authentication.

Prerequisites: @nestjs/passport, passport, passport-jwt, @nestjs/jwt

  1. Create an auth module:

    @Module({
      imports: [
        JwtModule.register({
          secret: 'your-secret-key',
          signOptions: { expiresIn: '1h' },
        }),
      ],
      providers: [AuthService, JwtStrategy],
      exports: [AuthService],
    })
    export class AuthModule {}
    
  2. Create a JWT strategy:

    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
      constructor() {
        super({
          jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
          secretOrKey: 'your-secret-key',
        });
      }
    
      async validate(payload: any) {
        return { userId: payload.sub, username: payload.username };
      }
    }
    
  3. Protect routes with @UseGuards(AuthGuard('jwt')).

File Upload

Goal: Handle file uploads using multer.

import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import { UploadedFile, UploadedFiles } from '@nestjs/common';

@Controller('upload')
export class UploadController {
  @Post('single')
  @UseInterceptors(FileInterceptor('file'))
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    return { filename: file.originalname, size: file.size };
  }

  @Post('multiple')
  @UseInterceptors(FilesInterceptor('files', 10))
  uploadFiles(@UploadedFiles() files: Express.Multer.File[]) {
    return files.map(f => ({ filename: f.originalname }));
  }
}

Server-Sent Events (SSE)

Goal: Stream real-time updates to clients.

import { Controller, Sse } from '@nestjs/common';
import { Observable, interval, map } from 'rxjs';

@Controller()
export class SseController {
  @Sse('events')
  events(): Observable<MessageEvent> {
    return interval(1000).pipe(
      map(() => ({ data: { timestamp: Date.now() } } as MessageEvent)),
    );
  }
}

Serve Static Files

Goal: Serve a frontend SPA alongside the API.

npm i @nestjs/serve-static
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'client'),
    }),
  ],
})
export class AppModule {}

WebSocket Gateway

Goal: Add real-time bidirectional communication.

npm i @nestjs/websockets @nestjs/platform-socket.io socket.io
import {
  WebSocketGateway,
  SubscribeMessage,
  MessageBody,
  WebSocketServer,
  ConnectedSocket,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway({ cors: true })
export class EventsGateway {
  @WebSocketServer()
  server: Server;

  @SubscribeMessage('message')
  handleMessage(
    @MessageBody() data: string,
    @ConnectedSocket() client: Socket,
  ): string {
    this.server.emit('broadcast', data);
    return 'Message received';
  }
}

Microservices (TCP Transport)

Goal: Create a microservice communicating over TCP.

// main.ts (microservice)
import { NestFactory } from '@nestjs/core';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    { transport: Transport.TCP, options: { host: '0.0.0.0', port: 3001 } },
  );
  await app.listen();
}
bootstrap();
// Controller handling messages
@Controller()
export class MathController {
  @MessagePattern({ cmd: 'sum' })
  sum(data: number[]): number {
    return data.reduce((a, b) => a + b, 0);
  }

  @EventPattern('user_created')
  handleUserCreated(data: any) {
    // Handle event (fire-and-forget)
  }
}

Dynamic Modules

Goal: Create a reusable, configurable module.

import { DynamicModule, Module } from '@nestjs/common';

@Module({})
export class ConfigModule {
  static forRoot(options: ConfigOptions): DynamicModule {
    return {
      module: ConfigModule,
      providers: [
        { provide: 'CONFIG_OPTIONS', useValue: options },
        ConfigService,
      ],
      exports: [ConfigService],
      global: true,
    };
  }
}

Tip

For complex dynamic modules, use ConfigurableModuleBuilder from @nestjs/common to auto-generate forRoot() and forRootAsync() static methods with less boilerplate.

MVC with Templates

Goal: Render server-side views using a template engine.

// main.ts
const app = await NestFactory.create(AppModule);
app.setBaseViewsDir(join(__dirname, '..', 'views'));
app.setViewEngine('hbs');
@Controller()
export class AppController {
  @Get()
  @Render('index')
  root() {
    return { message: 'Hello World' };
  }
}

Using StreamableFile for File Downloads

import { StreamableFile } from '@nestjs/common';
import { createReadStream } from 'fs';
import { join } from 'path';

@Controller('files')
export class FilesController {
  @Get('download')
  getFile(): StreamableFile {
    const file = createReadStream(join(process.cwd(), 'package.json'));
    return new StreamableFile(file);
  }
}

API Versioning

import { VersioningType } from '@nestjs/common';

const app = await NestFactory.create(AppModule);
app.enableVersioning({ type: VersioningType.URI });
@Controller({ path: 'cats', version: '1' })
export class CatsV1Controller { /* ... */ }

@Controller({ path: 'cats', version: '2' })
export class CatsV2Controller { /* ... */ }

Versioning types:

Type Example URL
VersioningType.URI /v1/cats
VersioningType.HEADER Header: X-API-Version: 1
VersioningType.MEDIA_TYPE Accept: application/json;v=1
VersioningType.CUSTOM Custom extraction logic

Using Swagger/OpenAPI

npm i @nestjs/swagger
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

const config = new DocumentBuilder()
  .setTitle('Cats API')
  .setDescription('The cats API description')
  .setVersion('1.0')
  .addBearerAuth()
  .build();

const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api-docs', app, document);

GraphQL (Code-First)

npm i @nestjs/graphql @nestjs/apollo @apollo/server graphql
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { GraphQLModule } from '@nestjs/graphql';

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: join(process.cwd(), 'schema.gql'),
    }),
  ],
})
export class AppModule {}

Class Serialization

Control what properties are exposed in responses:

import { ClassSerializerInterceptor, UseInterceptors } from '@nestjs/common';
import { Exclude, Expose } from 'class-transformer';

export class UserEntity {
  id: number;
  name: string;

  @Exclude()
  password: string;

  constructor(partial: Partial<UserEntity>) {
    Object.assign(this, partial);
  }
}

@Controller('users')
@UseInterceptors(ClassSerializerInterceptor)
export class UsersController {
  @Get(':id')
  findOne(@Param('id') id: string): UserEntity {
    return new UserEntity({ id: 1, name: 'John', password: 'secret' });
  }
}

6. Troubleshooting

Error: Nest can't resolve dependencies of the X

Cause: A provider's dependency is not available in the current module scope. The DI container cannot find a provider for the required injection token.

Solution:

  1. Ensure the dependency is listed in the providers array of the module
  2. If the dependency lives in another module, import that module and ensure it exports the provider
  3. For circular dependencies, use forwardRef():
    @Inject(forwardRef(() => CatsService))
    

Prevention: Keep module boundaries clear. Export only what other modules need.

Error: Unknown element or Unknown module

Cause: A module or provider is imported but not properly decorated or not a valid NestJS module.

Solution:

  1. Verify the class has the @Module() decorator
  2. Check for typos in import paths
  3. Ensure circular module dependencies use forwardRef()

Error: Cannot GET /path

Cause: No route handler matches the requested path.

Solution:

  1. Check the controller has @Controller('prefix') with the correct prefix
  2. Verify the route decorator (@Get(), @Post(), etc.) path matches
  3. If using global prefix, account for it: app.setGlobalPrefix('api') means routes become /api/...
  4. Check if versioning is enabled — routes may require version prefix

Application hangs on shutdown

Cause: Open connections or long-running tasks preventing graceful shutdown.

Solution:

  1. Enable shutdown hooks:
    app.enableShutdownHooks();
    
  2. Implement OnApplicationShutdown in providers that hold connections:
    @Injectable()
    export class DbService implements OnApplicationShutdown {
      onApplicationShutdown(signal?: string) {
        return this.connection.close();
      }
    }
    

Prevention: Always clean up resources in lifecycle hooks.

Error: Circular dependency between modules

Cause: Module A imports Module B, which imports Module A.

Solution: Use forwardRef() in both module imports:

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

Warning

Circular dependencies are a design smell. Refactor to extract shared functionality into a third module when possible.

Validation errors not thrown

Cause: ValidationPipe not applied or class-validator decorators missing.

Solution:

  1. Install required packages: npm i class-validator class-transformer
  2. Apply ValidationPipe globally or at the controller/method level
  3. Add validation decorators to DTO classes:
    import { IsString, IsInt, Min } from 'class-validator';
    
    export class CreateCatDto {
      @IsString()
      name: string;
    
      @IsInt()
      @Min(0)
      age: number;
    }
    

WebSocket connection refused

Cause: WebSocket gateway not properly registered or CORS blocking the connection.

Solution:

  1. Ensure the gateway class is registered in a module's providers
  2. Enable CORS on the gateway:
    @WebSocketGateway({ cors: { origin: '*' } })
    

Fastify middleware not working (nestjs/nest#11802)

Cause: Fastify middleware doesn't apply correctly when matched against routes registered via a Fastify plugin.

Solution: Register middleware before Fastify plugins, or use NestJS-level middleware (NestMiddleware) instead of Fastify-native middleware for routes managed by NestJS controllers.

7. FAQ

Q: How do I switch from Express to Fastify?

Replace @nestjs/platform-express with @nestjs/platform-fastify and update main.ts:

import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';

const app = await NestFactory.create<NestFastifyApplication>(
  AppModule,
  new FastifyAdapter(),
);
await app.listen(3000, '0.0.0.0');  // Fastify listens on localhost only by default

Q: What are injection scopes and when should I use them?

NestJS supports three scopes: DEFAULT (singleton), REQUEST (per-request instance), and TRANSIENT (new instance per injection). Most providers should use DEFAULT. Use REQUEST when you need per-request state (e.g., multi-tenant context). Use TRANSIENT when each consumer needs its own instance.

@Injectable({ scope: Scope.REQUEST })
export class RequestScopedService {}

Q: How do I create a hybrid application (HTTP + microservice)?

const app = await NestFactory.create(AppModule);
app.connectMicroservice<MicroserviceOptions>({
  transport: Transport.TCP,
  options: { port: 3001 },
});
await app.startAllMicroservices();
await app.listen(3000);

Q: How do I use the REPL mode?

import { repl } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  await repl(AppModule);
}
bootstrap();

This starts an interactive shell where you can call methods on any provider, inspect the DI container, and debug the application.

Q: How do I set up hot module replacement (HMR)?

Use the webpack-hmr.config.js with @nestjs/cli or, for ESM projects, configure HMR in main.ts:

declare const module: any;

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

  if (module.hot) {
    module.hot.accept();
    module.hot.dispose(() => app.close());
  }
}
bootstrap();

Q: What lifecycle hooks are available?

Hooks execute in this order during startup and shutdown:

Hook When
onModuleInit After the module's providers are instantiated
onApplicationBootstrap After all modules are initialized
onModuleDestroy When close() is called (reverse order)
beforeApplicationShutdown After onModuleDestroy, before connections close
onApplicationShutdown After all connections are closed

Q: How do I handle CORS?

const app = await NestFactory.create(AppModule);
app.enableCors({
  origin: ['https://example.com'],
  methods: 'GET,POST',
  credentials: true,
});

Q: Can I use NestJS with Babel instead of TypeScript?

Yes. NestJS provides a Babel example (sample/09-babel-example). Use @babel/plugin-proposal-decorators and @babel/plugin-proposal-class-properties for decorator support.

Q: How do I test NestJS applications?

Use @nestjs/testing to create a testing module:

import { Test, TestingModule } from '@nestjs/testing';

describe('CatsController', () => {
  let controller: CatsController;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [CatsController],
      providers: [CatsService],
    }).compile();

    controller = module.get<CatsController>(CatsController);
  });

  it('should return all cats', () => {
    expect(controller.findAll()).toBeDefined();
  });
});

Q: How do I use gRPC with NestJS?

const app = await NestFactory.createMicroservice<MicroserviceOptions>(
  AppModule,
  {
    transport: Transport.GRPC,
    options: {
      package: 'hero',
      protoPath: join(__dirname, 'hero/hero.proto'),
    },
  },
);

Define handlers with @GrpcMethod():

@Controller()
export class HeroController {
  @GrpcMethod('HeroService', 'FindOne')
  findOne(data: { id: number }): Hero {
    return { id: data.id, name: 'Hero' };
  }
}