Tags: nestjs, typescript, nodejs, backend, dependency-injection, architecture
Level: intermediate
TL;DR: Modular TypeScript backend framework using Angular-like architecture, inversion of control, and decorators on top of Express or Fastify.
Architecture is structured around Modules, Controllers, and Providers.
Modules organize application boundaries using @Module() with imports, controllers, and providers.
Controllers handle incoming HTTP requests and map routes with decorators like @Get() or @Post().
Providers encapsulate business logic and data access, annotated with @Injectable().
Built-in Inversion of Control (IoC) container resolves dependencies via constructor injection.
Middleware runs before route handlers, matching Express middleware mechanics.
Guards implement CanActivate to determine route access, authentication, and authorization.
Interceptors implement NestInterceptor using RxJS observables for logging, caching, and payload transformation.
Pipes implement PipeTransform for input validation and data transformation before handler execution.
Exception filters catch unhandled errors and format uniform client responses.
Q: How does Dependency Injection work in NestJS?R: Providers are marked with @Injectable(). The NestJS IoC container instantiates them as singletons by default and injects them into constructors declared in module providers.
Q: What is the difference between Middleware, Interceptors, and Guards?R: Middleware executes first without execution context. Guards check permissions and return a boolean. Interceptors wrap execution using RxJS for pre/post processing and response mapping.
Q: What is the difference between Express and Fastify adapters in NestJS?R: Express is the battle-tested default with broad compatibility. Fastify offers significantly higher throughput and lower overhead for performance-critical endpoints.
Q: How do you handle validation in NestJS request payloads?R: I use ValidationPipe globally or per route combined with class-validator and class-transformer decorators on DTO classes.
Forgetting to export a provider from its module makes it inaccessible to importing modules.
Circular module dependencies require forwardRef() in both module imports and constructor injections.
Default providers are singletons; setting Scope.REQUEST creates a new instance per request, increasing memory and CPU overhead.
Global pipes and filters defined outside APP_PIPE or APP_FILTER tokens bypass Nest dependency injection.
Unhandled RxJS observables in custom interceptors can cause request hangs or memory leaks.
# Nest CLI common commands
npm i -g @nestjs/cli
nest new my-api
nest g module users
nest g controller users
nest g service users
TypeScript
// DTO with validation
import { IsEmail, IsString, MinLength } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
}
TypeScript
// Controller and Service injection
import { Controller, Post, Body, Get, UseGuards } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { AuthGuard } from '../auth/auth.guard';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
async create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
@Get()
@UseGuards(AuthGuard)
async findAll() {
return this.usersService.findAll();
}
}
[ ] Custom parameter decorators using createParamDecorator
[ ] Dynamic modules using forRoot() and forRootAsync()
[ ] Lifecycle hooks: OnModuleInit, OnApplicationBootstrap, OnModuleDestroy
[ ] Microservices transports: Redis, NATS, and Kafka in NestJS
[x] Basic Module-Controller-Service structure
[x] Global ValidationPipe with DTOs
[x] Guard implementation with CanActivate
NestJS Official Documentation (docs.nestjs.com)
NestJS GitHub Repository (github.com/nestjs/nest)