PermissiveMITTested by Geekflare

NestJS review

TypeScript framework for Node.js servers with modules, dependency injection and decorators, on Express, Fastify or node:http

Data refreshedMethodologyHow we tested
Director of Geekflare

Rity Anand is a director of Geekflare. She has extensive experience managing business technology and a special interest in emerging technologies.

Verdict

NestJS gives TypeScript teams a fixed structure of modules, providers and decorators, with official packages for OpenAPI, WebSockets, microservice transports, authentication and the common ORMs. The catch is the amount of decorator and module code it asks for, the ESM-only move in version 12, and a steady run of security advisories in the Fastify adapter and microservices package over the past year.

Best for

TypeScript teams building larger APIs or microservices that want one agreed structure

Not for

Small services where plain routing is enough, or teams that need Bun, Deno or edge runtimes

Pros

  • Modules and dependency injection give every project the same layout
  • Runs on Express, Fastify or plain node:http through adapters
  • Official packages for OpenAPI, WebSockets, auth, TypeORM, Drizzle and Mongoose
  • Built-in microservice transports for Kafka, NATS, RabbitMQ, gRPC and more

Cons

  • Many security advisories in the last year, mostly Fastify middleware bypasses
  • Version 12 is ESM-only, which complicates upgrades of CommonJS apps and Jest suites
  • Leans on decorators and classes, which adds code compared with plain routing
What people say
Ask Sparkian

Is NestJS right for your project?

Describe what you need and AI will check the fit against this review.

Or try:

NestJS features and capabilities

Modules and dependency injection

Code is split into modules whose providers are injected by the framework, so large codebases keep one layout and services are easy to swap in tests.

Choice of HTTP layer

The same controllers run on Express, Fastify or the new node:http adapter, so a team can change the HTTP layer without rewriting routes.

OpenAPI from code

The official @nestjs/swagger module builds an OpenAPI document and Swagger UI from decorators, DTO classes or Zod and Valibot schemas.

Validation with classes or schemas

Request bodies, params and queries are checked by the built-in ValidationPipe with class-validator, or since version 12 by Standard Schema libraries such as Zod.

Microservice transports

Services can talk over TCP, Redis, NATS, MQTT, RabbitMQ, Kafka or gRPC with the same handler code, which suits teams splitting a monolith.

TypeScript firstWritten in TypeScript or ships its own types, with typed routes or handlers
Yes
Request validationValidates bodies, params or queries against a schema, in the core or an official package
YesValidationPipe with class-validator, or Standard Schema such as Zod
OpenAPI docsGenerates an OpenAPI spec or Swagger UI from routes
YesOfficial @nestjs/swagger module
Beyond Node.jsOfficially runs on Bun, Deno or edge runtimes such as Cloudflare Workers
NoNode.js only; Bun is supported as a package manager
WebSocketsBuilt in or through an official plugin
Yes@nestjs/websockets with socket.io or ws
Project structureModules, dependency injection or a fixed layout, not only routing
YesModules, providers and dependency injection
Database layerAn official ORM, query builder or data layer
PartlyOfficial modules for TypeORM, Drizzle, Sequelize and Mongoose; no ORM of its own
AuthenticationAn official auth module, plugin or strategy system
Yes@nestjs/authentication, plus @nestjs/passport and @nestjs/jwt

At a glance

Type
Progressive Node.js framework
Stack
TypeScript / Node.js 20.19+
Databases
PostgreSQL, MySQL, SQLite, SQL Server, MongoDB

Free vs paid editions

What you get when you self-host, and what needs a paid plan.

The framework and its official packages are MIT, and nothing in them needs a licence key. The Nest team sells Mau, a deployment service that provisions your app, databases and brokers on AWS from $12 a month plus your AWS bill, along with NestJS Observe for tracing, which is free up to 300,000 events a month, official courses and enterprise support.

Running NestJS

Running a Nest 12 app needs Node.js 20.19 or later, or 22.12 or later on the 22.x line, and the CLI generators need Node.js 22.22.3, 24.15 or 26.

New cloud server to ready

10 s

Memory in use at idle

106 MB of 4 GB

Reads per second

8,182

Writes per second

5,268

Startup

1.13 s

Version tested

12.3.2 · Oct 31, 2026

  • The app is one TypeScript file compiled with tsc: a DTO class with class-validator decorators, a controller and a module. Install plus build took 10 seconds and 81 MB including the TypeScript compiler, with 104 packages.
  • Nest 12 packages are ESM only, but the CommonJS build ran without changes on Node.js 24, which can require ES modules.
  • TypeScript 7 needed "types": ["node"] in tsconfig.json before it would see process. The build still emitted JavaScript without it.
  • ValidationPipe listed every invalid field, and NotFoundException gave a consistent JSON 404.
src/main.ts, after npm i @nestjs/common @nestjs/core @nestjs/platform-express reflect-metadata rxjs class-validator class-transformer
import "reflect-metadata";
import { Body, Controller, Get, HttpCode, Module, NotFoundException, Param, ParseIntPipe, Post, ValidationPipe } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
import { ArrayMaxSize, IsArray, IsNumber, IsOptional, IsString, Length, Min } from "class-validator";

class CreateItemDto {
  @IsString() @Length(1, 100) name: string;
  @IsNumber() @Min(0) price: number;
  @IsOptional() @IsArray() @IsString({ each: true }) @ArrayMaxSize(10) tags?: string[];
}

// 100 items kept in memory, so the test measures the framework, not a database.
const items = new Map<number, object>();
for (let i = 1; i <= 100; i++) items.set(i, { id: i, name: `Item ${i}`, price: i * 1.5, tags: ["sample"] });
let nextId = 101;

@Controller()
class ItemsController {
  @Get("health")
  health() { return { status: "ok" }; }

  @Get("items/:id")
  get(@Param("id", ParseIntPipe) id: number) {
    const item = items.get(id);
    if (!item) throw new NotFoundException("Not found");
    return item;
  }

  @Post("items")
  @HttpCode(201)
  create(@Body() body: CreateItemDto) {
    const item = { id: nextId++, ...body };
    items.set(item.id, item);
    return item;
  }
}

@Module({ controllers: [ItemsController] })
class AppModule {}

async function bootstrap() {
  const app = await NestFactory.create(AppModule, { logger: ["error", "warn"] });
  app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }));
  await app.listen(Number(process.env.PORT ?? 3000), "127.0.0.1");
}
bootstrap();
OutputPassed12.3.2 · 400, ValidationPipe's default error
Request: POST /items with {"name": "", "price": -1}
{
  "message": [
    "name must be longer than or equal to 1 characters",
    "price must not be less than 0"
  ],
  "error": "Bad Request",
  "statusCode": 400
}

What you can do with NestJS

Backend for a large product team

Give several teams one module layout, dependency injection and testing setup so services look the same across the codebase.

Event-driven microservices

Build services that exchange messages over Kafka, RabbitMQ or NATS with the same controllers and guards as the HTTP API.

Documented public API

Publish an OpenAPI document and Swagger UI generated from the controllers and DTOs, so client SDKs stay in step with the code.