Jesse A. Green / notebook

NestJS Administrator & Developer 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. Architecture Overview

NestJS is a TypeScript-first framework for building server-side Node.js applications. It provides a modular, decorator-driven architecture inspired by Angular, centered around dependency injection, a request processing pipeline, and platform-agnostic HTTP layer abstractions. The framework is published as a monorepo of packages under the @nestjs scope, each addressing a specific concern — from HTTP handling to microservices, WebSockets, and testing.

The core design philosophy separates the framework into three layers: the platform layer (HTTP adapters for Express or Fastify), the core layer (DI container, lifecycle management, routing, middleware pipeline), and the common layer (decorators, interfaces, pipes, exceptions, and utilities shared across all parts of the framework).

Architecture Diagram

                    ┌─────────────────────────────────────────┐
                    │              NestFactory                 │
                    │  create() / createMicroservice()         │
                    └─────────────┬───────────────────────────┘
                                  │
                    ┌─────────────▼───────────────────────────┐
                    │         NestApplication                  │
                    │  ┌──────────────────────────────────┐   │
                    │  │      ApplicationConfig            │   │
                    │  │  (global prefix, versioning,      │   │
                    │  │   pipes, guards, interceptors,    │   │
                    │  │   filters, WebSocket adapter)     │   │
                    │  └──────────────────────────────────┘   │
                    │  ┌──────────────────────────────────┐   │
                    │  │       NestContainer               │   │
                    │  │  ┌────────┐  ┌────────┐          │   │
                    │  │  │Module A│  │Module B│  ...      │   │
                    │  │  │ provs  │  │ provs  │          │   │
                    │  │  │ ctrls  │  │ ctrls  │          │   │
                    │  │  └────────┘  └────────┘          │   │
                    │  └──────────────────────────────────┘   │
                    │  ┌──────────────────────────────────┐   │
                    │  │    Request Pipeline               │   │
                    │  │  Middleware → Guards → Intercept  │   │
                    │  │  → Pipes → Handler → Intercept   │   │
                    │  │  → Exception Filters              │   │
                    │  └──────────────────────────────────┘   │
                    └─────────────┬───────────────────────────┘
                                  │
                    ┌─────────────▼───────────────────────────┐
                    │      Platform Adapter (HTTP)             │
                    │  ExpressAdapter  │  FastifyAdapter        │
                    └──────────────────────────────────────────┘

Component Inventory

Component Package Role
NestFactory @nestjs/core Bootstrap entry point; creates application instances
NestApplication @nestjs/core HTTP application with routing, middleware, lifecycle
NestApplicationContext @nestjs/core Standalone context (no HTTP) for workers, scripts, REPL
NestContainer @nestjs/core DI container holding all module instances and providers
Injector @nestjs/core Resolves and instantiates providers within the container
RoutesResolver @nestjs/core Maps controller decorators to HTTP routes
MiddlewareModule @nestjs/core Registers and executes middleware chains
ApplicationConfig @nestjs/core Global configuration state (prefix, pipes, guards, etc.)
MetadataScanner @nestjs/core Scans class prototypes for decorated methods
DiscoveryService @nestjs/core Programmatic access to all registered providers/controllers
Reflector @nestjs/core Read metadata set by decorators on classes/methods
LazyModuleLoader @nestjs/core Load modules on demand at runtime
SerializedGraph / GraphInspector @nestjs/core Inspect the dependency graph for debugging
ExpressAdapter @nestjs/platform-express Wraps Express for NestJS
FastifyAdapter @nestjs/platform-fastify Wraps Fastify for NestJS
IoAdapter @nestjs/platform-socket.io Socket.IO WebSocket adapter
WsAdapter @nestjs/platform-ws ws library WebSocket adapter
ClientsModule @nestjs/microservices Registers microservice client proxies
Server (abstract) @nestjs/microservices Base class for all transport servers
ClientProxy (abstract) @nestjs/microservices Base class for all transport clients
Test @nestjs/testing Creates testing module instances

Technology Stack

Technology Role Version
TypeScript Primary language 5.x
Node.js Runtime >= 20
Express Default HTTP adapter 5.x
Fastify Alternative HTTP adapter 5.x
RxJS Reactive programming / interceptor pipeline 7.x
reflect-metadata Decorator metadata reflection 0.2.x
iterare Lazy iteration utilities 1.2.x
path-to-regexp Route pattern matching 8.x
uid Unique ID generation (mixin naming) 2.x
tslib TypeScript helper library 2.x

Data Flow: HTTP Request

  1. HTTP request arrives at the platform adapter (Express/Fastify)
  2. Global middleware executes in registration order
  3. Module-scoped middleware executes for matching routes
  4. Guards evaluate (canActivate) — reject returns 403 Forbidden
  5. Pre-handler interceptors execute (intercept before next.handle())
  6. Pipes transform/validate parameters
  7. Route handler executes
  8. Post-handler interceptors process the response Observable
  9. Exception filters catch any thrown errors, format the response
  10. Response is sent to the client

2. System Requirements

Requirement Minimum Recommended
Node.js 20.x Latest LTS
npm 9.x Latest
TypeScript 5.0+ 5.9+
OS Linux, macOS, Windows Any
Memory 256 MB 512 MB+

TypeScript Configuration Requirements

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "ES2021",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "strictNullChecks": true,
    "declaration": true,
    "sourceMap": true,
    "outDir": "./dist"
  }
}

Important

emitDecoratorMetadata and experimentalDecorators are mandatory. Without them, dependency injection based on constructor parameter types will not work.

ESM Support

NestJS supports ECMAScript Modules (ESM) from Node.js 22+. For ESM projects, set "type": "module" in package.json and use the load-esm package (bundled dependency) for dynamic imports of ESM-only packages. Sample applications 34-using-esm-packages and 35-use-esm-package-after-node22 demonstrate the pattern.

3. Configuration Reference

NestFactory.create() Options

Option Type Default Description
logger LogLevel[] | LoggerService | false All levels Controls logging output
abortOnError boolean true Throw during bootstrap on init errors
snapshot boolean false Enable dependency graph snapshotting
preview boolean false Preview mode — no HTTP listener
forceCloseConnections boolean false Force-close keep-alive connections on shutdown
cors boolean | CorsOptions false Enable CORS
bodyParser boolean true Enable built-in body parsing
rawBody boolean false Attach raw body buffer to request
httpsOptions HttpsOptions undefined TLS/SSL configuration

Application Instance Methods

Method Description
app.listen(port, host?) Start HTTP server
app.getUrl() Get the bound URL (call after listen())
app.setGlobalPrefix(prefix, options?) Set a global route prefix
app.enableVersioning(options) Enable API versioning
app.useGlobalPipes(...pipes) Register global validation/transform pipes
app.useGlobalGuards(...guards) Register global authorization guards
app.useGlobalInterceptors(...interceptors) Register global interceptors
app.useGlobalFilters(...filters) Register global exception filters
app.useWebSocketAdapter(adapter) Set WebSocket adapter
app.connectMicroservice(options) Attach a microservice transport
app.startAllMicroservices() Start all connected microservices
app.enableShutdownHooks(signals?) Listen for OS shutdown signals
app.enableCors(options?) Enable CORS with options
app.useLogger(logger) Replace the default logger
app.flushLogs() Flush buffered log messages
app.select(module) Navigate to a specific module context
app.get(token, options?) Retrieve a provider instance
app.resolve(token, contextId?, options?) Resolve a request/transient-scoped provider
app.init() Initialize without starting the listener
app.close() Gracefully shut down
app.useBodyParser(type, options?) Configure body parser (Express adapter)
app.setBaseViewsDir(path) Set MVC views directory
app.setViewEngine(engine) Set MVC template engine

Environment Variables

Variable Effect
NO_COLOR Disables ANSI color codes in logger output
NEST_DEBUG Enables verbose DI container debug logging (shows injection resolution)

Note

NEST_DEBUG is extremely verbose and intended for debugging circular dependency or missing provider issues. Do not enable in production.

Global Prefix Options

app.setGlobalPrefix('api', {
  exclude: [
    { path: 'health', method: RequestMethod.GET },
    { path: '/', method: RequestMethod.GET },
  ],
});

Versioning Options

Property Type Description
type VersioningType URI, HEADER, MEDIA_TYPE, or CUSTOM
defaultVersion string | string[] Default version for unversioned controllers
header string Header name (for HEADER type)
key string Media type key (for MEDIA_TYPE type)
extractor Function Custom version extractor (for CUSTOM type)

Module-Level Registration via APP_* Tokens

Instead of app.useGlobal*(), register enhancers within the DI system using special tokens:

import { APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER } from '@nestjs/core';

@Module({
  providers: [
    { provide: APP_GUARD, useClass: AuthGuard },
    { provide: APP_PIPE, useClass: ValidationPipe },
    { provide: APP_INTERCEPTOR, useClass: LoggingInterceptor },
    { provide: APP_FILTER, useClass: AllExceptionsFilter },
  ],
})
export class AppModule {}

Tip

Using APP_* tokens allows enhancers to participate in dependency injection (they can inject other providers). app.useGlobal*() registers instances outside the DI container.

4. Deployment & Scaling

Production Build

npm run build        # Compile TypeScript → dist/
node dist/main.js    # Run production build

For monorepo workspaces:

npx tsc -b -v packages   # Build all packages

Fastify Adapter (Production)

Fastify provides significantly higher throughput than Express. Switch by replacing the platform package:

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

const app = await NestFactory.create<NestFastifyApplication>(
  AppModule,
  new FastifyAdapter({ logger: true }),
);
await app.listen(3000, '0.0.0.0');

Warning

Fastify binds to localhost by default. In containerized environments, you must bind to 0.0.0.0 or the container's network interface.

Docker Deployment

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["node", "dist/main.js"]

Webpack Bundling

NestJS supports Webpack for bundling applications into a single file:

nest build --webpack

Sample 08-webpack demonstrates this pattern with HotModuleReplacementPlugin for development.

Graceful Shutdown

const app = await NestFactory.create(AppModule);
app.enableShutdownHooks();

// Or with specific signals and options:
app.enableShutdownHooks([ShutdownSignal.SIGTERM, ShutdownSignal.SIGINT], {
  useProcessExit: true,  // Required for async loggers (e.g., Pino with transports)
});

Shutdown signal lifecycle:

  1. Signal received → onModuleDestroy() (reverse module order)
  2. beforeApplicationShutdown(signal) (reverse module order)
  3. Server connections closed
  4. onApplicationShutdown(signal) (reverse module order)
  5. Process exits

Hybrid Applications (HTTP + Microservices)

const app = await NestFactory.create(AppModule);

// Attach a TCP microservice
app.connectMicroservice<MicroserviceOptions>({
  transport: Transport.TCP,
  options: { host: '0.0.0.0', port: 3001 },
});

// Attach a Redis microservice
app.connectMicroservice<MicroserviceOptions>({
  transport: Transport.REDIS,
  options: { host: 'localhost', port: 6379 },
});

await app.startAllMicroservices();
await app.listen(3000);

5. Operations

Logging

NestJS ships with a built-in Logger and ConsoleLogger service.

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

@Injectable()
export class CatsService {
  private readonly logger = new Logger(CatsService.name);

  findAll() {
    this.logger.log('Fetching all cats');
    this.logger.warn('This is a warning');
    this.logger.error('Something failed', stackTrace);
    this.logger.debug('Debug info');
    this.logger.verbose('Verbose info');
  }
}

Log levels (in order): verbose, debug, log, warn, error, fatal

Configure at bootstrap:

const app = await NestFactory.create(AppModule, {
  logger: ['error', 'warn', 'log'],
});

Tip

Replace the built-in logger with a production logger (Winston, Pino, etc.) by implementing LoggerService and calling app.useLogger(myLogger).

Note

The ConsoleLogger class can be extended for custom formatting while retaining NestJS's log level filtering logic. Unlike Logger (which is a static wrapper), ConsoleLogger is instantiable and supports dependency injection.

Health Checks

Use @nestjs/terminus (separate package) for health check endpoints:

npm i @nestjs/terminus
@Controller('health')
export class HealthController {
  constructor(
    private health: HealthCheckService,
    private db: TypeOrmHealthIndicator,
  ) {}

  @Get()
  check() {
    return this.health.check([
      () => this.db.pingCheck('database'),
    ]);
  }
}

Monitoring and Metrics

The DiscoveryService and GraphInspector from @nestjs/core provide introspection capabilities:

import { DiscoveryService } from '@nestjs/core';

@Injectable()
export class MetricsService {
  constructor(private readonly discovery: DiscoveryService) {}

  getProviderCount(): number {
    return this.discovery.getProviders().length;
  }

  getControllerCount(): number {
    return this.discovery.getControllers().length;
  }
}

Note

A community feature request for a native metrics module exists (nestjs/nest#967) but is not yet implemented. Use third-party packages like @willsoto/nestjs-prometheus or custom interceptors for request metrics.

REPL Mode

Start an interactive REPL for debugging and exploration:

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

async function bootstrap() {
  const replServer = await repl(AppModule);
  replServer.setupHistory('.nestjs_repl_history', (err) => {
    if (err) console.error(err);
  });
}
bootstrap();
npx ts-node repl.ts

Built-in REPL functions:

Function Description
get(token) Retrieve a provider instance
resolve(token) Resolve a request/transient-scoped provider
select(module) Navigate to a specific module
debug() Print all registered modules, controllers, providers
methods(token) List available methods on a provider
$(token) Shorthand for get(token)

6. Performance

Express vs. Fastify

The repository includes a benchmark suite (tools/benchmarks/) that compares Express and Fastify adapters:

Framework Relative Performance
Fastify (raw) Baseline
NestJS + Fastify ~95% of raw Fastify
Express (raw) ~60-70% of Fastify
NestJS + Express ~55-65% of Fastify

Tip

For high-throughput APIs, use @nestjs/platform-fastify. The Fastify adapter supports fast-json-stringify for schema-based response serialization, which can further improve throughput for JSON-heavy APIs.

Injection Scopes and Performance

Scope Instantiation Performance Impact
DEFAULT (singleton) Once at startup None — cached instance
REQUEST Per HTTP request Moderate — creates new instance tree per request
TRANSIENT Per injection High — creates new instance per consumer per request

Warning

REQUEST scope propagates up the dependency chain. If a singleton depends on a request-scoped provider, the singleton must also become request-scoped. Design the dependency graph carefully to avoid unintended scope bubbling.

Lazy Module Loading

Load modules on demand to reduce startup time:

@Injectable()
export class AppService {
  constructor(private readonly loader: LazyModuleLoader) {}

  async loadReporting() {
    const { ReportingModule } = await import('./reporting/reporting.module');
    const moduleRef = await this.loader.load(() => ReportingModule);
    const service = moduleRef.get(ReportingService);
    return service.generateReport();
  }
}

7. Security

CORS Configuration

app.enableCors({
  origin: ['https://example.com', 'https://admin.example.com'],
  methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
  credentials: true,
  allowedHeaders: 'Content-Type,Authorization',
  exposedHeaders: 'X-Total-Count',
  maxAge: 3600,
});

Helmet Integration

npm i helmet
import helmet from 'helmet';

const app = await NestFactory.create(AppModule);
app.use(helmet());

Rate Limiting

npm i @nestjs/throttler
@Module({
  imports: [
    ThrottlerModule.forRoot({ ttl: 60, limit: 10 }),
  ],
})
export class AppModule {}

Authentication Patterns

NestJS integrates with Passport.js for authentication. The sample 19-auth-jwt demonstrates JWT authentication with:

  1. JwtStrategy extending PassportStrategy(Strategy) — validates JWT tokens
  2. AuthService — handles login logic and token generation
  3. JwtAuthGuard extending AuthGuard('jwt') — protects routes
  4. Public decorator — marks routes as public (skips authentication)
// Public decorator pattern from sample 19
export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);

Exception Handling Security

The built-in exception layer prevents stack traces from leaking to clients in production. HttpException responses include only the status code and message. Enable detailed errors only in development:

// Avoid in production
GraphQLModule.forRoot({
  includeStacktraceInErrorResponses: false,  // Default: false
});

Caution

Never expose internal error details, stack traces, or database error messages to clients. Always catch and transform internal exceptions into appropriate HTTP exceptions with safe messages.

File Upload Validation

Use ParseFilePipe with built-in validators:

@Post('upload')
@UseInterceptors(FileInterceptor('file'))
uploadFile(
  @UploadedFile(
    new ParseFilePipe({
      validators: [
        new MaxFileSizeValidator({ maxSize: 10 * 1024 * 1024 }),  // 10 MB
        new FileTypeValidator({ fileType: 'image/jpeg' }),
      ],
    }),
  )
  file: Express.Multer.File,
) {
  return { filename: file.originalname };
}

8. Developer Internals

Repository Structure

nestjs/nest/
├── packages/                    # Framework source (published to npm)
│   ├── common/                  # Shared decorators, interfaces, pipes, exceptions
│   │   ├── decorators/          # @Controller, @Injectable, @Module, @Inject, etc.
│   │   │   ├── core/            # Core decorators (DI, lifecycle, metadata)
│   │   │   ├── http/            # HTTP method + param decorators
│   │   │   └── modules/         # @Module, @Global
│   │   ├── enums/               # HttpStatus, RequestMethod, Scope, VersioningType
│   │   ├── exceptions/          # All HTTP exception classes
│   │   ├── file-stream/         # StreamableFile
│   │   ├── interfaces/          # TypeScript interfaces for the entire framework
│   │   ├── module-utils/        # ConfigurableModuleBuilder
│   │   ├── pipes/               # Built-in pipes (Validation, Parse*, File)
│   │   ├── serializer/          # ClassSerializerInterceptor
│   │   ├── services/            # Logger, ConsoleLogger
│   │   └── utils/               # Shared utilities
│   ├── core/                    # Framework engine
│   │   ├── adapters/            # AbstractHttpAdapter
│   │   ├── discovery/           # DiscoveryService, DiscoveryModule
│   │   ├── errors/              # Framework-level error classes
│   │   ├── exceptions/          # BaseExceptionFilter, ExceptionsHandler
│   │   ├── guards/              # GuardsConsumer, GuardsContextCreator
│   │   ├── helpers/             # ContextIdFactory, ExecutionContext utilities
│   │   ├── hooks/               # Lifecycle hook callers
│   │   ├── injector/            # DI container, Injector, Module, InstanceWrapper
│   │   ├── inspector/           # GraphInspector, SerializedGraph
│   │   ├── interceptors/        # InterceptorsConsumer, InterceptorsContextCreator
│   │   ├── middleware/           # MiddlewareModule, MiddlewareContainer
│   │   ├── pipes/               # PipesConsumer, PipesContextCreator
│   │   ├── repl/                # REPL mode implementation
│   │   ├── router/              # RoutesResolver, RouterExplorer, RouterModule
│   │   └── services/            # Reflector
│   ├── microservices/           # Microservice transports
│   │   ├── client/              # ClientProxy implementations per transport
│   │   ├── ctx-host/            # Transport-specific context classes
│   │   ├── decorators/          # @MessagePattern, @EventPattern, @Client, etc.
│   │   ├── deserializers/       # Message deserializers
│   │   ├── enums/               # Transport enum
│   │   ├── events/              # Event/message pattern handling
│   │   ├── exceptions/          # RpcException, microservice exception filters
│   │   ├── helpers/             # Kafka/NATS/MQTT helpers
│   │   ├── module/              # ClientsModule
│   │   ├── record-builders/     # NatsRecord, RmqRecord, MqttRecord, KafkaRecord
│   │   ├── serializers/         # Message serializers
│   │   ├── server/              # Server implementations per transport
│   │   └── utils/               # Shared microservice utilities
│   ├── platform-express/        # Express adapter
│   │   ├── adapters/            # ExpressAdapter
│   │   └── multer/              # File upload interceptors
│   ├── platform-fastify/        # Fastify adapter
│   │   ├── adapters/            # FastifyAdapter
│   │   └── decorators/          # @InjectRawBody, Fastify-specific decorators
│   ├── platform-socket.io/      # Socket.IO WebSocket adapter
│   ├── platform-ws/             # ws WebSocket adapter
│   ├── testing/                 # Test utilities (Test.createTestingModule)
│   └── websockets/              # WebSocket gateway system
│       ├── adapters/            # AbstractWsAdapter
│       ├── decorators/          # @WebSocketGateway, @SubscribeMessage, etc.
│       ├── errors/              # WS error classes
│       ├── exceptions/          # WsException, WsExceptionFilter
│       └── utils/               # Gateway metadata accessor
├── integration/                 # Integration test suites
│   ├── cors/                    # CORS integration tests
│   ├── hello-world/             # Basic HTTP integration
│   ├── hooks/                   # Lifecycle hooks tests
│   ├── injector/                # DI system tests (circular deps, scopes)
│   ├── inspector/               # Graph inspector tests
│   ├── lazy-modules/            # Lazy loading tests
│   ├── microservices/           # All transport integration tests
│   ├── mongoose/                # Mongoose integration
│   ├── nest-application/        # Application-level tests (SSE, body parser, etc.)
│   ├── repl/                    # REPL integration tests
│   ├── scopes/                  # Injection scope tests
│   ├── send-files/              # StreamableFile tests
│   ├── typeorm/                 # TypeORM integration
│   ├── versioning/              # API versioning tests
│   └── websockets/              # WebSocket integration tests
├── sample/                      # 36 example applications
├── tools/                       # Build and benchmark tools
│   ├── benchmarks/              # Express vs Fastify performance comparison
│   └── gulp/                    # Build pipeline tasks
├── lerna.json                   # Monorepo config (version: 11.1.19)
└── package.json                 # Root dependencies and scripts

Architecture Deep Dive

Dependency Injection System

The DI system is the foundation of NestJS. It operates through these core classes:

NestContainer — The top-level container holding a Map<string, Module> of all registered modules. Each module is identified by a token generated from its class and dynamic metadata.

Module (internal) — Represents a single @Module() class. Contains three collections:

  • _providers — Map of provider wrappers (InstanceWrapper)
  • _controllers — Map of controller wrappers
  • _imports — Set of imported module references

InstanceWrapper — Wraps a provider/controller instance with metadata: scope, injection token, resolved value, and per-context instance maps for REQUEST/TRANSIENT scopes.

Injector — The resolution engine. For each provider, it:

  1. Reads constructor parameter types via reflect-metadata
  2. Resolves each parameter's injection token
  3. Looks up the matching InstanceWrapper in the module tree
  4. Recursively instantiates dependencies
  5. Caches singleton instances; creates new instances for request/transient scopes

Injection scopes:

Scope Constant Behavior
Singleton Scope.DEFAULT One instance shared across all consumers (default)
Request Scope.REQUEST New instance per HTTP request / microservice message
Transient Scope.TRANSIENT New instance per injection point

Durable providers (durable: true in @Injectable()) can persist across requests when used with a custom ContextIdStrategy.

Module Resolution Order

  1. NestFactory.create() calls the DependenciesScanner
  2. Scanner recursively traverses imports from the root module
  3. Each module is compiled (metadata extracted, token generated)
  4. The InstanceLoader instantiates all providers in dependency order
  5. onModuleInit hooks fire in topological order (leaf modules first)
  6. onApplicationBootstrap hooks fire in the same order

Lifecycle Hooks

Hook Interface Method When
OnModuleInit onModuleInit() After provider instantiation, before app is ready
OnApplicationBootstrap onApplicationBootstrap() After all modules initialized
OnModuleDestroy onModuleDestroy() On close(), reverse module order
BeforeApplicationShutdown beforeApplicationShutdown(signal?) After destroy, before connections close
OnApplicationShutdown onApplicationShutdown(signal?) Final hook, after connections closed

All hooks support async (Promise) return values. Modules are processed in topological distance order on init, and reverse order on shutdown.

Router System

The RoutesResolver scans all controllers and their methods:

  1. Reads PATH_METADATA from @Controller() for the base path
  2. Reads HTTP method metadata from @Get(), @Post(), etc.
  3. Reads parameter metadata from @Body(), @Param(), etc.
  4. Creates route handlers that execute the pipeline (guards → interceptors → pipes → handler)
  5. Registers routes with the platform adapter

Route parameter extraction uses RouteParamtypes enum values (REQUEST=0, RESPONSE=1, NEXT=2, BODY=3, QUERY=4, PARAM=5, HEADERS=6, SESSION=7, FILE=8, FILES=9, HOST=10, IP=11, RAW_BODY=12).

Platform Adapters

Both adapters extend AbstractHttpAdapter and implement a common interface:

ExpressAdapter:

  • Wraps Express 5.x
  • Supports multer for file uploads (FileInterceptor, FilesInterceptor, FileFieldsInterceptor, AnyFilesInterceptor)
  • Body parsing enabled by default (JSON + URL-encoded)
  • Versioning supports URI, HEADER, MEDIA_TYPE, and CUSTOM types

FastifyAdapter:

  • Wraps Fastify 5.x
  • Uses @fastify/multipart for file uploads
  • Uses @fastify/middie for Express-style middleware compatibility
  • Uses @fastify/cors for CORS
  • Uses @fastify/static for static file serving
  • Uses @fastify/view for template rendering
  • Supports @fastify/formbody for form data parsing
  • Provides @InjectRawBody() decorator for raw body access

Microservices Architecture

Transport Implementations

Transport Server Class Client Class Package
TCP ServerTCP ClientTCP @nestjs/microservices
Redis ServerRedis ClientRedis @nestjs/microservices + ioredis
NATS ServerNats ClientNats @nestjs/microservices + nats
MQTT ServerMqtt ClientMqtt @nestjs/microservices + mqtt
RabbitMQ ServerRMQ ClientRMQ @nestjs/microservices + amqplib
Kafka ServerKafka ClientKafka @nestjs/microservices + kafkajs
gRPC ServerGrpc ClientGrpc @nestjs/microservices + @grpc/grpc-js

All servers extend the abstract Server class. All clients extend ClientProxy.

Message Patterns

  • @MessagePattern(pattern) — Request/response (client sends, expects a reply)
  • @EventPattern(pattern) — Event-based (fire-and-forget, no reply)
  • @GrpcMethod(service, method) — gRPC unary/server-streaming
  • @GrpcStreamMethod(service, method) — gRPC client-streaming/bidirectional

Context Classes

Each transport provides a specialized context:

Transport Context Class Key Methods
TCP TcpContext getSocketRef(), getPattern()
Redis RedisContext getChannel(), getPattern()
NATS NatsContext getSubject(), getHeaders()
MQTT MqttContext getTopic(), getPacket()
RabbitMQ RmqContext getMessage(), getChannelRef(), getPattern()
Kafka KafkaContext getMessage(), getTopic(), getPartition(), getConsumer(), getProducer(), getHeartbeat()

All extend BaseRpcContext.

Record Builders

For transport-specific message metadata:

Builder Purpose
NatsRecordBuilder Attach NATS headers to messages
RmqRecordBuilder Attach RabbitMQ options (persistent, expiration, headers)
MqttRecordBuilder Attach MQTT options (QoS, retain, properties)
KafkaRecordBuilder Attach Kafka headers, key, partition

ClientsModule Registration

@Module({
  imports: [
    ClientsModule.register([
      { name: 'MATH_SERVICE', transport: Transport.TCP, options: { port: 3001 } },
    ]),
    // Or async:
    ClientsModule.registerAsync([
      {
        name: 'MATH_SERVICE',
        useFactory: (config: ConfigService) => ({
          transport: Transport.TCP,
          options: { port: config.get('MATH_PORT') },
        }),
        inject: [ConfigService],
      },
    ]),
  ],
})
export class AppModule {}

Serialization Layer

Custom serializers/deserializers transform messages between wire format and application format:

Class Direction
IdentitySerializer Passthrough (default for most transports)
KafkaRequestSerializer Encodes Kafka message key/value/headers
IncomingRequestDeserializer Deserializes request patterns
IncomingEventDeserializer Deserializes event patterns
KafkaRequestDeserializer Decodes Kafka messages
NatsRequestJSONDeserializer Decodes NATS JSON messages
NatsResponseJSONDeserializer Decodes NATS JSON responses
MqttRecordSerializer Serializes MQTT records
NatsRecordSerializer Serializes NATS records
RmqRecordSerializer Serializes RMQ records

WebSocket System

The @WebSocketGateway() decorator registers a class as a WebSocket gateway. The WebSocketsController discovers all gateways, creates server instances via the configured adapter, and binds message handlers.

Decorators:

Decorator Purpose
@WebSocketGateway(port?, options?) Mark class as WebSocket gateway
@SubscribeMessage(event) Handle a specific message event
@WebSocketServer() Inject the underlying server instance
@ConnectedSocket() Inject the client socket
@MessageBody(property?) Extract message body or a property

Gateway hooks:

Interface Method
OnGatewayInit afterInit(server)
OnGatewayConnection handleConnection(client, ...args)
OnGatewayDisconnect handleDisconnect(client)

Testing

@nestjs/testing provides Test.createTestingModule() for creating isolated test modules:

const moduleRef = await Test.createTestingModule({
  imports: [CatsModule],
  providers: [
    { provide: CatsService, useValue: mockCatsService },
  ],
})
  .overrideProvider(CatsService)
  .useValue(mockCatsService)
  .overrideGuard(AuthGuard)
  .useValue({ canActivate: () => true })
  .compile();

Override methods:

Method Target
overrideProvider(token) Replace a provider
overrideGuard(guard) Replace a guard
overrideInterceptor(interceptor) Replace an interceptor
overridePipe(pipe) Replace a pipe
overrideFilter(filter) Replace an exception filter
overrideModule(module) Replace an entire module

Each returns a builder with .useClass(), .useValue(), and .useFactory().

Code Patterns and Conventions

Decorator pattern: NestJS uses TypeScript decorators extensively with reflect-metadata for storing configuration metadata on classes and methods. All framework decorators write metadata using Reflect.defineMetadata().

Observable-based pipeline: Interceptors use RxJS Observable chains. The CallHandler.handle() returns an Observable of the route handler's response, allowing operators like map, tap, catchError, and timeout to be chained.

Commit conventions: The repo uses Angular-style commits (feat, fix, chore, etc.) with scopes matching package names (common, core, microservices, express, fastify, socket.io, ws, testing, websockets).

Build system: TypeScript project references (tsc -b) compile all packages. Gulp tasks handle file copying, sample builds, and module relocation. Lerna manages versioning and publishing.

Testing: Unit tests use Mocha + Chai + Sinon. Integration tests live in integration/ with per-feature directories. Docker Compose (integration/docker-compose.yml) provides Redis, NATS, MQTT, MySQL, MongoDB, RabbitMQ, ZooKeeper, and Kafka for transport integration tests.

Key Interfaces

Interface Package Purpose
INestApplication @nestjs/common HTTP application contract
INestApplicationContext @nestjs/common Standalone context contract
INestMicroservice @nestjs/common Microservice contract
CanActivate @nestjs/common Guard interface
NestInterceptor @nestjs/common Interceptor interface
PipeTransform @nestjs/common Pipe interface
ExceptionFilter @nestjs/common Exception filter interface
NestMiddleware @nestjs/common Middleware interface
OnModuleInit @nestjs/common Lifecycle hook
OnApplicationBootstrap @nestjs/common Lifecycle hook
OnModuleDestroy @nestjs/common Lifecycle hook
BeforeApplicationShutdown @nestjs/common Lifecycle hook
OnApplicationShutdown @nestjs/common Lifecycle hook
Type<T> @nestjs/common Class constructor type
DynamicModule @nestjs/common Dynamic module metadata
ModuleMetadata @nestjs/common Static module metadata
CustomDecorator @nestjs/common Return type of SetMetadata()

ConfigurableModuleBuilder

Generates forRoot(), forRootAsync(), MODULE_OPTIONS_TOKEN, and ConfigurableModuleAsyncOptions for dynamic modules:

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

export interface HttpModuleOptions {
  baseUrl: string;
  timeout?: number;
}

export const {
  ConfigurableModuleClass,
  MODULE_OPTIONS_TOKEN,
  OPTIONS_TYPE,
  ASYNC_OPTIONS_TYPE,
} = new ConfigurableModuleBuilder<HttpModuleOptions>()
  .setClassMethodName('forRoot')
  .setExtras({ isGlobal: false }, (definition, extras) => ({
    ...definition,
    global: extras.isGlobal,
  }))
  .build();

Reflector Service

The Reflector class (from @nestjs/core) reads metadata set by @SetMetadata():

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

// Use
@Roles('admin')
@Get()
findAll() {}

// Read in 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;
    const request = context.switchToHttp().getRequest();
    return roles.includes(request.user?.role);
  }
}

Reflector methods:

Method Description
get(key, target) Get metadata from a single target
getAll(key, targets) Get metadata from multiple targets
getAllAndMerge(key, targets) Merge metadata arrays from multiple targets
getAllAndOverride(key, targets) Get first non-undefined metadata

9. Integration Points

Database Integrations

NestJS provides official wrappers for database ORMs as separate packages:

Package ORM Database Types
@nestjs/typeorm TypeORM MySQL, PostgreSQL, SQLite, SQL Server, Oracle
@nestjs/mongoose Mongoose MongoDB
@nestjs/sequelize Sequelize MySQL, PostgreSQL, SQLite, SQL Server

Each provides forRoot() / forRootAsync() and forFeature() patterns for module-level configuration.

GraphQL

Package Purpose
@nestjs/graphql GraphQL module with code-first and schema-first approaches
@nestjs/apollo Apollo Server driver
@nestjs/mercurius Mercurius (Fastify-native) driver

Federation support: Samples 31-graphql-federation-code-first and 32-graphql-federation-schema-first demonstrate Apollo Federation with gateway + subgraph patterns.

Caching

import { CacheModule } from '@nestjs/cache-manager';

@Module({
  imports: [CacheModule.register({ ttl: 5, max: 100 })],
})
export class AppModule {}

Use @UseInterceptors(CacheInterceptor) for automatic GET response caching.

Task Scheduling

npm i @nestjs/schedule
import { Cron, Interval, Timeout } from '@nestjs/schedule';

@Injectable()
export class TasksService {
  @Cron('0 */5 * * * *')
  handleCron() { /* every 5 minutes */ }

  @Interval(10000)
  handleInterval() { /* every 10 seconds */ }

  @Timeout(5000)
  handleTimeout() { /* once after 5 seconds */ }
}

Event Emitter

npm i @nestjs/event-emitter
import { EventEmitter2 } from '@nestjs/event-emitter';

@Injectable()
export class OrdersService {
  constructor(private eventEmitter: EventEmitter2) {}

  create(order: Order) {
    this.eventEmitter.emit('order.created', new OrderCreatedEvent(order));
  }
}

@Injectable()
export class OrderCreatedListener {
  @OnEvent('order.created')
  handleOrderCreatedEvent(event: OrderCreatedEvent) {
    // Handle event
  }
}

Queues

npm i @nestjs/bull bull
@Module({
  imports: [
    BullModule.forRoot({
      redis: { host: 'localhost', port: 6379 },
    }),
    BullModule.registerQueue({ name: 'audio' }),
  ],
})
export class AppModule {}

Docker Compose for Integration Testing

The repository's integration/docker-compose.yml provisions all external services needed for transport tests:

Service Image Port
Redis redis 6379
NATS nats 4222, 8222
MQTT eclipse-mosquitto 1883, 9001
MySQL mysql:9.6.0 3306
MongoDB mongo:latest 27017
RabbitMQ rabbitmq:management 5672, 15672
ZooKeeper confluentinc/cp-zookeeper:7.9.6 2181
Kafka confluentinc/cp-kafka:8.2.0 9092, 29092
docker-compose -f integration/docker-compose.yml up -d
npm run test:integration
docker-compose -f integration/docker-compose.yml down

Note

KafkaJS, the Kafka client used by NestJS, appears to be no longer actively maintained (nestjs/nest#13223). Monitor for potential migration to an alternative client library.

Build Scripts

Script Purpose
npm run build Compile all packages (tsc -b)
npm run build:prod Clean build for release
npm run test Run unit tests (Mocha)
npm run test:integration Run integration tests
npm run test:cov Run tests with coverage
npm run test:docker:up Start Docker services for integration tests
npm run test:docker:down Stop Docker services
npm run lint Lint packages, integration, and spec files
npm run format Format with Prettier
npm run publish Build and publish via Lerna

Contributing

The repository uses:

  • Commit format: Angular-style (feat(core): add feature, fix(microservices): fix bug)
  • Linting: ESLint with Prettier integration
  • Pre-commit: Husky + lint-staged (auto-formats .ts and .json files)
  • CI: CircleCI for build/test/lint
  • Code coverage: nyc + Coveralls
  • Monorepo management: Lerna (version 9.x)

Known Issues

Issue Status Impact
nestjs/nest#13223 Open KafkaJS maintenance concerns
nestjs/nest#16257 Open Nested transient providers not isolated in static context
nestjs/nest#11802 Open Fastify middleware route matching with plugins
nestjs/nest#14590 Open Concurrent Kafka topic consumption
nestjs/nest#6771 Open Socket.IO forwardEventNameAs option for IoAdapter
nestjs/nest#1953 Open gRPC exception filter support
nestjs/nest#967 Open Native metrics module feature request