OpenAPI / Swagger Documentation
Good APIs are not just functional — they are discoverable. OpenAPI (the specification) and Swagger UI (the interactive browser interface) give every consumer a live, self-describing contract for your endpoints. NestJS ships first-class support through @nestjs/swagger, which reads your TypeScript decorators and generates the spec automatically.
Installation and setup
npm install @nestjs/swagger
Bootstrap Swagger in main.ts using SwaggerModule and DocumentBuilder:
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('Tasks API')
.setDescription('Manage user tasks')
.setVersion('1.0')
.addBearerAuth() // adds the Authorize button for JWT
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api-docs', app, document); // UI at /api-docs
await app.listen(3000);
}
bootstrap();
Generate once, serve forever. SwaggerModule.createDocument() scans every controller and DTO in your application graph and produces a JSON document conforming to the OpenAPI 3.0 specification. The raw JSON is available at /api-docs-json for tooling integration.
@ApiTags — grouping controllers
Tag a controller so its endpoints are grouped under a named section in the UI:
import { Controller, Get } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
@ApiTags('tasks')
@Controller('tasks')
export class TasksController {
@Get()
findAll() { /* ... */ }
}
Documenting DTOs with @ApiProperty
@ApiProperty annotates each field of a DTO, giving Swagger the type, description, example value, and validation constraints for the request body schema:
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsString, IsNotEmpty, IsOptional, IsEnum } from 'class-validator';
export enum TaskStatus {
OPEN = 'OPEN',
IN_PROGRESS = 'IN_PROGRESS',
DONE = 'DONE',
}
export class CreateTaskDto {
@ApiProperty({ description: 'Short task title', example: 'Write unit tests' })
@IsString()
@IsNotEmpty()
title: string;
@ApiPropertyOptional({
description: 'Longer description',
example: 'Cover all service methods with Jest',
})
@IsOptional()
@IsString()
description?: string;
@ApiProperty({ enum: TaskStatus, default: TaskStatus.OPEN })
@IsEnum(TaskStatus)
status: TaskStatus;
}
Use @ApiPropertyOptional for optional fields. It is shorthand for @ApiProperty({ required: false }) and keeps your DTO annotations concise. Always add an example value — it makes the "Try it out" feature actually useful.
@ApiResponse — documenting return types
Decorate individual route handlers to describe possible HTTP responses, including the shape of the returned data:
import { Get, Param } from '@nestjs/common';
import {
ApiOkResponse,
ApiNotFoundResponse,
ApiUnauthorizedResponse,
} from '@nestjs/swagger';
import { Task } from './task.entity';
@Get(':id')
@ApiOkResponse({ type: Task, description: 'The task record' })
@ApiNotFoundResponse({ description: 'Task not found' })
@ApiUnauthorizedResponse({ description: 'Missing or invalid JWT' })
findOne(@Param('id') id: string) {
return this.tasksService.findOne(id);
}
For the entity class itself, annotate its properties the same way you annotate DTO fields:
import { ApiProperty } from '@nestjs/swagger';
export class Task {
@ApiProperty({ example: 'f47ac10b-58cc-4372-a567-0e02b2c3d479' })
id: string;
@ApiProperty({ example: 'Write unit tests' })
title: string;
@ApiProperty({ enum: TaskStatus })
status: TaskStatus;
}
@ApiBearerAuth — protecting routes in the UI
When a route requires a JWT, add @ApiBearerAuth() so the Swagger UI sends the token from the Authorize dialog:
import { UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
@ApiTags('tasks')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'))
@Controller('tasks')
export class TasksController { /* ... */ }
Never expose Swagger in production without authentication. The SwaggerModule.setup() call can be wrapped in a check such as if (process.env.NODE_ENV !== 'production'), or protected behind HTTP basic auth using the customSiteTitle / Express middleware approach. A public Swagger UI leaks your full API surface area to attackers.
Summary
@nestjs/swagger generates an OpenAPI 3.0 document directly from your decorators. Install the package, call SwaggerModule.setup() in main.ts, and then annotate controllers with @ApiTags, DTOs with @ApiProperty, handlers with @ApiResponse variants, and protected routes with @ApiBearerAuth(). The result is a live, interactive Swagger UI that doubles as executable documentation for every API consumer on your team.