Suggest an editImprove this articleRefine the answer for “What is NestJS and what problems does it solve?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**NestJS** is a TypeScript Node.js framework that adds Angular-style modules, decorators, and built-in dependency injection on top of Express. ```typescript @Controller('users') export class UsersController { constructor(private usersService: UsersService) {} @Get() getUsers() { return this.usersService.findAll(); } } ``` **Key idea:** Express gives total freedom with no rules; NestJS enforces a module-per-domain layout so teams can grow without turning the codebase into spaghetti.Shown above the full answer for quick recall.Answer (EN)Image**NestJS** is a TypeScript-based Node.js framework that puts Angular-style structure (modules, decorators, dependency injection) on top of Express to build scalable server-side applications. ## Theory ### TL;DR - NestJS is like taking scattered Express files and putting each feature into a labeled bag: one module per domain, all wired together automatically - Main difference: Express has zero rules; NestJS enforces a folder contract through decorators and modules - Under the hood it still runs Express (or Fastify), so NestJS is a layer on top, not a replacement - Decision rule: solo prototype under a week? Use Express. Team project or API with 5+ endpoints? NestJS ### Quick example The same GET /users endpoint in both approaches: ```typescript // Express: works fine, but where does this go as the app grows? const express = require('express'); const app = express(); app.get('/users', (req, res) => res.json([{ id: 1, name: 'Alice' }])); app.listen(3000); // NestJS: auto-discovered via decorators, one clear location per feature import { Controller, Get } from '@nestjs/common'; @Controller('users') export class UsersController { @Get() getUsers() { return [{ id: 1, name: 'Alice' }]; // GET /users → [{"id":1,"name":"Alice"}] } } // Start with: nest start (scans modules automatically) ``` For three routes, Express is fine. For thirty routes across five developers with no agreed structure, it falls apart fast. ### Key difference Express hands you a blank canvas. Routes go anywhere, imports are manual, no rules exist. NestJS draws the lines first: every feature lives in a **module** (like Angular's NgModule), controllers handle HTTP via decorators (`@Get`, `@Post`), and services hold logic with dependencies injected through the constructor. This removes the classic team argument of "where does this route actually live?" that shows up in every code review on unstructured Express projects. ### When to use - Solo prototype, under a week: Express (no learning curve, faster start) - Team project or API with 5+ endpoints: NestJS (structure stops merge conflicts before they start) - Microservices or WebSockets: NestJS (built-in via `@nestjs/microservices` and `@nestjs/websockets`) - High traffic, 10k+ RPS: NestJS with the Fastify adapter (roughly 2x throughput over Express default) ### Comparison table | Aspect | Express | NestJS | Fastify | Koa | |--------|---------|--------|---------|-----| | **TypeScript** | Optional | Built-in | Optional | Optional | | **Structure** | None | Modules enforce layout | None | Minimal | | **DI container** | Manual | Built-in | Manual | Manual | | **Decorators** | No | Yes | No | No | | **CLI** | No | Yes (`nest` CLI) | No | No | | **Learning curve** | ~1 hour | ~1 day | ~1 hour | ~2 hours | | **Best for** | Scripts, small apps | Team APIs, large backends | High-perf APIs | Lightweight middleware | ### How NestJS bootstraps NestJS scans your `main.ts`, reads TypeScript decorators (`@Module`, `@Controller`) using Node's `reflect-metadata` package, builds a dependency graph, and instantiates providers in the correct order. Then it registers Express route handlers from your decorator-annotated methods. All of this runs before the first request arrives. ```typescript // main.ts import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); // scans decorators, builds DI graph await app.listen(3000); } bootstrap(); ``` Teams I have seen move from plain Express to NestJS say the same thing after the first month: they spend less time arguing about where to put new code. ### Common mistakes **Dumping all routes into app.controller.ts:** ```typescript // Wrong: one controller becomes the entire app @Controller() export class AppController { @Get('users') getUsers() { ... } @Get('products') getProducts() { ... } @Post('orders') createOrder() { ... } // 500 lines later, nothing is testable in isolation } ``` Modules exist specifically to prevent this. One controller per domain. `users.controller.ts` handles users only. **Creating services manually instead of using DI:** ```typescript // Wrong constructor() { this.service = new UsersService(); // bypasses the DI container } // Right constructor(private service: UsersService) {} // auto-injected as singleton ``` Manual `new` breaks auto-mocking in tests and skips singleton scoping. This is the most common NestJS mistake on Stack Overflow. **Forgetting to register providers in the module:** ```typescript // Wrong: service missing from providers array @Module({ controllers: [UsersController], // providers: [UsersService] <- not listed }) export class UsersModule {} // Result: injection fails, 404 in production with no clear error message ``` NestJS ignores any provider not listed in `providers`. Always register your services there. ### Real-world usage - Adidas: NestJS modules for orders and inventory, GraphQL via `@nestjs/graphql` - Autodesk: microservices with Kafka through `@nestjs/microservices` - Auth flows: `@nestjs/passport` + `@nestjs/jwt` is the standard combination across most NestJS projects - WebSocket apps: `@nestjs/websockets` with a Socket.io gateway ### Follow-up questions **Q:** Walk through what happens when NestJS starts. What does `NestFactory.create()` do? **A:** It scans `AppModule`, reflects over every `@Module` decorator using `reflect-metadata`, builds a dependency graph, and instantiates providers in dependency order. Then it registers Express route handlers. `app.listen(3000)` binds the HTTP server last. **Q:** What is the difference between a provider and a controller? **A:** Controllers handle HTTP: they receive requests and return responses. Providers (marked `@Injectable()`) hold business logic and can be injected anywhere. A controller calls a provider; a provider should not know HTTP exists. **Q:** How do you switch from Express to Fastify? **A:** Pass a `FastifyAdapter` to `NestFactory.create(AppModule, new FastifyAdapter())`. All decorators stay exactly the same. Fastify gives roughly 2x throughput at high load. **Q:** What is the execution order of guards, pipes, and interceptors? **A:** Guard runs first (auth check). Pipe runs next (validates and transforms input). Interceptor wraps the controller call, running before and after. Exception filter catches anything that throws. This order is fixed by NestJS internals. **Q:** How would you design a NestJS backend for 1 million requests per day? **A:** Separate modules per domain, Redis caching via `@nestjs/cache-manager`, health checks with `@nestjs/terminus`, transient scope for stateful services, and horizontal scaling via Kubernetes with microservices communicating through message queues. ## Examples ### Basic: module, controller, and service wired together ```typescript // users.module.ts import { Module } from '@nestjs/common'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; @Module({ controllers: [UsersController], providers: [UsersService], // NestJS injects this into the controller automatically }) export class UsersModule {} // users.service.ts import { Injectable } from '@nestjs/common'; @Injectable() export class UsersService { private users = [{ id: 1, name: 'Bob', email: 'bob@example.com' }]; findAll() { return this.users; } findOne(id: number) { return this.users.find(u => u.id === id); } } // users.controller.ts import { Controller, Get, Param } from '@nestjs/common'; import { UsersService } from './users.service'; @Controller('users') export class UsersController { constructor(private usersService: UsersService) {} // injected automatically @Get() getUsers() { return this.usersService.findAll(); } // GET /users → all users @Get(':id') getUser(@Param('id') id: string) { return this.usersService.findOne(+id); // GET /users/1 → single user object } } ``` `UsersService` is listed in `providers`, so NestJS creates one singleton instance and passes it into the controller constructor. No `new`, no manual imports beyond the type. ### Intermediate: input validation with a DTO and ValidationPipe ```typescript // create-user.dto.ts import { IsString, IsEmail, MinLength } from 'class-validator'; export class CreateUserDto { @IsString() @MinLength(2) name: string; @IsEmail() email: string; } // users.controller.ts (POST endpoint added) import { Controller, Post, Body, UsePipes, ValidationPipe } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; @Controller('users') export class UsersController { @Post() @UsePipes(new ValidationPipe()) createUser(@Body() dto: CreateUserDto) { // Bad input never reaches this line return { message: `Created user ${dto.name}` }; } } // POST /users with { "name": "A", "email": "notanemail" } // → 400: ["name must be longer than or equal to 2 characters", "email must be an email"] ``` `ValidationPipe` reads the class-validator decorators on your DTO and rejects bad input before it reaches controller logic. No manual if-checks needed. ### Advanced: resolving circular dependencies with forwardRef ```typescript // cats.service.ts import { Injectable, forwardRef, Inject } from '@nestjs/common'; import { DogsService } from '../dogs/dogs.service'; @Injectable() export class CatsService { constructor( @Inject(forwardRef(() => DogsService)) private dogsService: DogsService, ) {} meow() { return 'meow'; } } // dogs.service.ts import { Injectable, forwardRef, Inject } from '@nestjs/common'; import { CatsService } from '../cats/cats.service'; @Injectable() export class DogsService { constructor( @Inject(forwardRef(() => CatsService)) private catsService: CatsService, ) {} bark() { return this.catsService.meow() + ' woof'; } } // Without forwardRef on both sides: // → Error: "Cannot resolve dependency CatsService" at startup ``` Circular dependencies usually signal a design problem worth fixing. But when you genuinely need two services that depend on each other, `forwardRef` lets NestJS resolve them at runtime instead of crashing at startup. Mark it as technical debt and schedule the refactor.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.