NestJS Basics
10 examples to understand the NestJS 11 mental model - 7 basic and 3 intermediate.
Search across all documentation pages
10 examples to understand the NestJS 11 mental model - 7 basic and 3 intermediate.
npm i -g @nestjs/cli@11
nest new my-api --strict
cd my-api
npm pkg set type=moduleFor DI patterns and cross-cutting concerns, see Dependency Injection and Guards, Interceptors & Pipes.
// users.module.ts
import { Module } from "@nestjs/common";
import { UsersController } from "./users.controller.js";
import { UsersService } from "./users.service.js";
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}// users.service.ts
import { Injectable } from "@nestjs/common";
@Injectable()
export class UsersService {
findAll() {
return [{ id: 1, name: "Ada Lovelace" }];
}
}// users.controller.ts
import { Controller, Get } from "@nestjs/common";
import { UsersService } from "./users.service.js";
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
}@Module groups related controllers and providers@Injectable marks a class for DI@Controller defines route prefix; methods define HTTP verbsimport { Controller, Get, Post, Body, Param } from "@nestjs/common";
@Controller("users")
export class UsersController {
@Get(":id")
findOne(@Param("id") id: string) {
return { id, name: "Ada" };
}
@Post()
create(@Body() body: { name: string; email: string }) {
return { id: "1", ...body };
}
}@Param("id") extracts route parameters@Body() extracts request body (parsed by underlying adapter)// app.module.ts
import { Module } from "@nestjs/common";
import { UsersModule } from "./users/users.module.js";
@Module({
imports: [UsersModule],
})
export class AppModule {}// main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module.js";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();AppModule is the root; import feature modulesNestFactory.create bootstraps the DI containerNestFactory.create(AppModule, new FastifyAdapter()) for performanceasync function bootstrap() {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix("api/v1");
await app.listen(3000);
}/api/v1setGlobalPrefix("api", { exclude: ["health"] })import { ValidationPipe } from "@nestjs/common";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
await app.listen(3000);
}import { IsEmail, IsString, MinLength } from "class-validator";
export class CreateUserDto {
@IsString()
@MinLength(1)
name!: string;
@IsEmail()
email!: string;
}whitelist: true strips unknown propertiestransform: true converts plain objects to DTO class instancesclass-validator and class-transformerimport { 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(exception.getResponse());
}
}@Catch(HttpException) scopes to HTTP exceptionsimport { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
@Module({
imports: [ConfigModule.forRoot({ isGlobal: true })],
})
export class AppModule {}import { Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
@Injectable()
export class AppService {
constructor(private config: ConfigService) {}
getPort() {
return this.config.get<number>("PORT", 3000);
}
}@nestjs/config loads .env filesConfigService injects environment valuesimport { NestFactory } from "@nestjs/core";
import { FastifyAdapter, NestFastifyApplication } from "@nestjs/platform-fastify";
import { AppModule } from "./app.module.js";
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter({ logger: true })
);
await app.listen({ port: 3000, host: "0.0.0.0" });
}
bootstrap();@Module({
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
@Module({
imports: [UsersModule],
controllers: [OrdersController],
})
export class OrdersModule {}
// OrdersController can inject UsersServiceexports makes providers available to importing modulesexports, providers are private to the moduleimport { Injectable, OnModuleInit, OnModuleDestroy } from "@nestjs/common";
@Injectable()
export class DatabaseService implements OnModuleInit, OnModuleDestroy {
async onModuleInit() {
console.log("Connecting to database...");
}
async onModuleDestroy() {
console.log("Closing database connections...");
}
}onModuleInit runs after module dependencies are resolvedonModuleDestroy runs on graceful shutdownNestJS when you need DI, modular architecture, guards/interceptors, and microservices patterns. Fastify for lean APIs. See Framework Selection Checklist.
Yes. NestJS 11 supports Express 5 and Fastify 5 adapters on Node 24 LTS.
Strongly recommended. NestJS is decorator-driven and designed for TypeScript. JavaScript works but loses type safety.
Similar mental model: modules, DI, decorators, guards. NestJS is the closest Node equivalent.
Yes with "type": "module" and .js extensions in imports. Check NestJS 11 ESM docs for current support status.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 16, 2026