OpenAPI (Swagger)
Warning The techniques in this section require TypeScript, and are not available if your app is written using vanilla JavaScript.
The OpenAPI specification is a language-agnostic definition format used to describe RESTful APIs. Nest provides a dedicated module which allows generating such a specification by leveraging decorators.
Installation#
To begin using it, we first install the required dependencies.
$ npm install --save @nestjs/swagger swagger-ui-express
If you use fastify, install fastify-swagger
instead of swagger-ui-express
:
$ npm install --save @nestjs/swagger fastify-swagger
Bootstrap#
Once the installation process is complete, open the main.ts
file and initialize Swagger using the SwaggerModule
class:
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ApplicationModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
const options = new DocumentBuilder()
.setTitle('Cats example')
.setDescription('The cats API description')
.setVersion('1.0')
.addTag('cats')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
The DocumentBuilder
helps to structure a base document that conforms to the OpenAPI Specification. It provides several methods that allow setting such properties as title, description, version, etc. In order to create a full document (with all HTTP routes defined) we use the createDocument()
method of the SwaggerModule
class. This method takes two arguments, an application instance and a Swagger options object.
Once we create a document, we can call setup()
method. It accepts:
- the path to mount the Swagger UI
- an application instance
- the document object instantiated above
Now you can run the following command to start the HTTP server:
$ npm run start
While the application is running, open your browser and navigate to http://localhost:3000/api
. You should see the Swagger UI.

The SwaggerModule
automatically reflects all of your endpoints. Also, in order to display the Swagger UI, @nestjs/swagger
makes use of either swagger-ui-express
or fastify-swagger
depending on the platform.
Hint To generate and download a Swagger JSON file, navigate tohttp://localhost:3000/api-json
in your browser (assuming that your Swagger documentation is available underhttp://localhost:3000/api
).
Route parameters#
The SwaggerModule
searches for all @Body()
, @Query()
, and @Param()
decorators in route handlers to generate the API document. It also creates corresponding model definitions by taking advantage of reflection. Consider the following code:
@Post()
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
Hint To explicitly set the body definition use the@ApiBody()
decorator (@nestjs/swagger
package).
Based on the CreateCatDto
, the module definition will be created:

As you can see, the definition is empty although the class has a few declared properties. In order to make the class properties visible to the SwaggerModule
, we have to either annotate them with the @ApiProperty()
decorator or use a CLI plugin (read more in the Plugin section) which will do it automatically:
import { ApiProperty } from '@nestjs/swagger';
export class CreateCatDto {
@ApiProperty()
name: string;
@ApiProperty()
age: number;
@ApiProperty()
breed: string;
}
Hint Consider using the Swagger plugin (see Plugin section) which will automatically do it for you.
Let's open the browser and verify the generated CreateCatDto
model:

In addition, the @ApiProperty()
decorator allows setting various Schema Object properties:
@ApiProperty({
description: 'The age of a cat',
min: 1,
default: 1,
})
age: number;
Hint Instead of explicitly typing the@ApiProperty({ required: false })
you can use@ApiPropertyOptional()
short-hand decorator.
In order to explicitly set the type of the property, use the type
key:
@ApiProperty({
type: Number,
})
age: number;
Enums#
To identify an enum
, we must manually set the enum
property on the @ApiProperty
with an array of values.
@ApiProperty({ enum: ['Admin', 'Moderator', 'User']})
role: UserRole;
Alternatively, define an actual TypeScript enum as follows:
export enum UserRole {
Admin = 'Admin',
Moderator = 'Moderator',
User = 'User',
}
You can then use the enum directly with the @Query()
parameter decorator in combination with the @ApiQuery()
decorator.
@ApiQuery({ name: 'role', enum: UserRole })
async filterByRole(@Query('role') role: UserRole = UserRole.User) {}

With isArray
set to true, the enum
can be selected as a multi-select:

Arrays#
When the property is an array, we must manually indicate the array type as shown below:
@ApiProperty({ type: [String] })
names: string[];
Either include the type as the first element of an array (as shown above) or set the isArray
property to true
.
Circular dependencies#
When you have circular dependencies between classes, use a lazy function to provide the SwaggerModule
with type information:
@ApiProperty({ type: () => Node })
node: Node;
Generics and interfaces#
Since TypeScript does not store metadata about generics or interfaces, when you use them in your DTOs, SwaggerModule
may not be able to properly generate model definitions at runtime. For instance, below code won't be correctly inspected by the Swagger module:
createBulk(@Body() usersDto: CreateUserDto[])
In order to overcome this limitation, you can set the type explicitly:
@ApiBody({ type: [CreateUserDto] })
createBulk(@Body() usersDto: CreateUserDto[])
Raw definitions#
In some specific scenarios (e.g. deeply nested arrays, matrices), you may want to describe your type by hand.
@ApiProperty({
type: 'array',
items: {
type: 'array',
items: {
type: 'number',
},
},
})
coords: number[][];
Likewise, in order to define your input/output content manually in controller classes, use the schema
property:
@ApiBody({
schema: {
type: 'array',
items: {
type: 'array',
items: {
type: 'number',
},
},
},
})
async create(@Body() coords: number[][]) {}
Extra models#
In order to define additional models that should be inspected by Swagger module, use the @ApiExtraModels()
decorator:
@ApiExtraModels(ExtraModel)
export class CreateCatDto {}
Then, you can get the reference ($ref
) to your model using getSchemaPath(ExtraModel)
:
'application/vnd.api+json': {
schema: { $ref: getSchemaPath(ExtraModel) },
},
oneOf, anyOf, allOf#
In order to combine schemas, you can use oneOf
, anyOf
or allOf
keywords (read more).
@ApiProperty({
oneOf: [
{ $ref: getSchemaPath(Cat) },
{ $ref: getSchemaPath(Dog) },
],
})
pet: Cat | Dog;
HintgetSchemaPath()
function is imported from@nestjs/swagger
.
Both Cat
and Dog
must be defined as extra models using the @ApiExtraModels()
decorator (at the class-level).
Multiple specifications#
The SwaggerModule
provides a way to support multiple specifications. In other words, you can serve different documentation, with different UIs, on different endpoints.
To support multiple specifications, your application must be written with a modular approach. The createDocument()
method takes in a 3rd argument, extraOptions
, which is an object with a the property include
. The include
property has a value which is an array of modules.
You can setup multiple specifications support as shown below:
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ApplicationModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
/**
* createDocument(application, configurationOptions, extraOptions);
*
* createDocument method takes in an optional 3rd argument "extraOptions"
* which is an object with "include" property where you can pass an Array
* of Modules that you want to include in that Swagger Specification
* E.g: CatsModule and DogsModule will have two separate Swagger Specifications which
* will be exposed on two different SwaggerUI with two different endpoints.
*/
const options = new DocumentBuilder()
.setTitle('Cats example')
.setDescription('The cats API description')
.setVersion('1.0')
.addTag('cats')
.build();
const catDocument = SwaggerModule.createDocument(app, options, {
include: [CatsModule],
});
SwaggerModule.setup('api/cats', app, catDocument);
const secondOptions = new DocumentBuilder()
.setTitle('Dogs example')
.setDescription('The dogs API description')
.setVersion('1.0')
.addTag('dogs')
.build();
const dogDocument = SwaggerModule.createDocument(app, secondOptions, {
include: [DogsModule],
});
SwaggerModule.setup('api/dogs', app, dogDocument);
await app.listen(3000);
}
bootstrap();
Now you can start your server with the following command:
$ npm run start
Navigate to http://localhost:3000/api/cats
to see the Swagger UI for cats:

In turn, http://localhost:3000/api/dogs
will expose the Swagger UI for dogs:

Tags#
To attach a controller to a specific tag, use the @ApiTags(...tags)
decorator.
@ApiTags('cats')
@Controller('cats')
export class CatsController {}
Headers#
To define custom headers that are expected as part of the request, use @ApiHeader()
.
@ApiHeader({
name: 'Authorization',
description: 'Auth token',
})
@Controller('cats')
export class CatsController {}
Responses#
To define a custom HTTP response, we use @ApiResponse()
decorator.
@Post()
@ApiResponse({ status: 201, description: 'The record has been successfully created.'})
@ApiResponse({ status: 403, description: 'Forbidden.'})
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
Nest provides a set of short-hand API response decorators that inherit from the @ApiResponse
decorator:
@ApiOkResponse()
@ApiCreatedResponse()
@ApiBadRequestResponse()
@ApiUnauthorizedResponse()
@ApiNotFoundResponse()
@ApiForbiddenResponse()
@ApiMethodNotAllowedResponse()
@ApiNotAcceptableResponse()
@ApiRequestTimeoutResponse()
@ApiConflictResponse()
@ApiGoneResponse()
@ApiPayloadTooLargeResponse()
@ApiUnsupportedMediaTypeResponse()
@ApiUnprocessableEntityResponse()
@ApiInternalServerErrorResponse()
@ApiNotImplementedResponse()
@ApiBadGatewayResponse()
@ApiServiceUnavailableResponse()
@ApiGatewayTimeoutResponse()
@ApiDefaultResponse()
@Post()
@ApiCreatedResponse({ description: 'The record has been successfully created.'})
@ApiForbiddenResponse({ description: 'Forbidden.'})
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
To specify a return model for a request, we must create a class and annotate all properties with the @ApiProperty()
decorator.
export class Cat {
@ApiProperty()
id: number;
@ApiProperty()
name: string;
@ApiProperty()
age: number;
@ApiProperty()
breed: string;
}
Then, Cat
model must be used in combination with the type
property of the response decorator.
@ApiTags('cats')
@Controller('cats')
export class CatsController {
@Post()
@ApiCreatedResponse({
description: 'The record has been successfully created.',
type: Cat,
})
async create(@Body() createCatDto: CreateCatDto): Promise<Cat> {
return this.catsService.create(createCatDto);
}
}
Let's open the browser and verify the generated Cat
model:

Global prefix#
To ignore a global prefix for routes set through setGlobalPrefix()
, use ignoreGlobalPrefix
:
const document = SwaggerModule.createDocument(app, options, {
ignoreGlobalPrefix: true,
});
Security#
To define which security mechanisms should be used for a specific operation, use the @ApiSecurity()
decorator.
@ApiSecurity('basic')
@Controller('cats')
export class CatsController {}
Before you run your application, remember to add the security definition to your base document using DocumentBuilder
:
const options = new DocumentBuilder().addSecurity('basic', {
type: 'http',
scheme: 'basic',
});
Some of the most popular authentication techniques are predefined (e.g. basic
and bearer
) and therefore you don't have to define security mechanisms manually as shown above.
Basic authentication#
To enable basic authentication, use @ApiBasicAuth()
.
@ApiBasicAuth()
@Controller('cats')
export class CatsController {}
Before you run your application, remember to add the security definition to your base document using DocumentBuilder
:
const options = new DocumentBuilder().addBasicAuth();
Bearer authentication#
To enable bearer authentication, use @ApiBearerAuth()
.
@ApiBearerAuth()
@Controller('cats')
export class CatsController {}
Before you run your application, remember to add the security definition to your base document using DocumentBuilder
:
const options = new DocumentBuilder().addBearerAuth();
OAuth2 authentication#
To enable OAuth2, use @ApiOAuth2()
.
@ApiOAuth2(['pets:write'])
@Controller('cats')
export class CatsController {}
Before you run your application, remember to add the security definition to your base document using DocumentBuilder
:
const options = new DocumentBuilder().addOAuth2();
File upload#
You can enable file upload for a specific method with the @ApiBody
decorator together with @ApiConsumes()
. Here's a full example using the File Upload technique:
@UseInterceptors(FileInterceptor('file'))
@ApiConsumes('multipart/form-data')
@ApiBody({
description: 'List of cats',
type: FileUploadDto,
})
uploadFile(@UploadedFile() file) {}
Where FileUploadDto
is defined as follows:
class FileUploadDto {
@ApiProperty({ type: 'string', format: 'binary' })
file: any;
}
Decorators#
All of the available OpenAPI decorators have an Api
prefix to distinguish them from the core decorators. Below is a full list of the exported decorators along with a designation of the level at which the decorator may be applied.
@ApiOperation() | Method |
@ApiResponse() | Method / Controller |
@ApiProduces() | Method / Controller |
@ApiConsumes() | Method / Controller |
@ApiBearerAuth() | Method / Controller |
@ApiOAuth2() | Method / Controller |
@ApiBasicAuth() | Method / Controller |
@ApiSecurity() | Method / Controller |
@ApiExtraModels() | Method / Controller |
@ApiBody() | Method |
@ApiParam() | Method |
@ApiQuery() | Method |
@ApiHeader() | Method / Controller |
@ApiExcludeEndpoint() | Method |
@ApiTags() | Method / Controller |
@ApiProperty() | Model |
@ApiPropertyOptional() | Model |
@ApiHideProperty() | Model |
Plugin#
TypeScript's metadata reflection system has several limitations which make it impossible to, for instance, determine what properties a class consists of or recognize whether a given property is optional or required. However, some of these constraints can be addressed at compilation time. Nest provides a plugin that enhances the TypeScript compilation process to reduce the amount of boilerplate code required.
Hint This plugin is opt-in. If you prefer, you can declare all decorators manually, or only specific decorators where you need them.
The Swagger plugin will automatically:
- annotate all DTO properties with
@ApiProperty
unless@ApiHideProperty
is used - set the
required
property depending on the question mark (e.g.name?: string
will setrequired: false
) - set the
type
orenum
property depending on the type (supports arrays as well) - set the
default
property based on the assigned default value - set several validation rules based on
class-validator
decorators (ifclassValidatorShim
set totrue
) - add a response decorator to every endpoint with a proper status and
type
(response model)
Previously, if you wanted to provide an interactive experience with the Swagger UI,
you had to duplicate a lot of code to let the package knows how your models/components should be declared in the specification. For example, you could define a simple CreateUserDto
class as follows:
export class CreateUserDto {
@ApiProperty()
email: string;
@ApiProperty()
password: string;
@ApiProperty({ enum: RoleEnum, default: [], isArray: true })
roles: RoleEnum[] = [];
@ApiProperty({ required: false, default: true })
isEnabled?: boolean = true;
}
While it's not a big deal with medium-sized projects, it becomes pretty verbose & clunky once you have a large set of classes.
Now, with the Swagger plugin enabled, the above class definition can be declared simply:
export class CreateUserDto {
email: string;
password: string;
roles: RoleEnum[] = [];
isEnabled?: boolean = true;
}
The plugin adds appropriate decorators on the fly based on the Abstract Syntax Tree. Hence, you no longer have to struggle with @ApiProperty
decorators scattered throughout the entire project.
Hint The plugin will automatically generate any missing swagger properties, but if you need to override them, you simply set them explicitly via @ApiProperty()
.
In order to enable the plugin, simply open nest-cli.json
(if you use Nest CLI) and add the following plugins
configuration:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": ["@nestjs/swagger/plugin"]
}
}
You can use the options
property to customize the behavior of the plugin.
"plugins": [
{
"name": "@nestjs/swagger/plugin",
"options": {
"classValidatorShim": false
}
}
]
The options
property has to fulfill the following interface:
export interface PluginOptions {
dtoFileNameSuffix?: string[];
controllerFileNameSuffix?: string[];
classValidatorShim?: boolean;
}
Option | Default | Description |
---|---|---|
dtoFileNameSuffix | ['.dto.ts', '.entity.ts'] | DTO (Data Transfer Object) files suffix |
controllerFileNameSuffix | .controller.ts | Controller files suffix |
classValidatorShim | true | If set to true, the module will reuse class-validator validation decorators (e.g. @Max(10) will add max: 10 to schema definition) |
If you don't use the CLI but instead have a custom webpack
configuration, you can use this plugin in combination with ts-loader
:
getCustomTransformers: (program: any) => ({
before: [require('@nestjs/swagger/plugin').before({}, program)]
}),
Migration to 4.0#
If you're currently using @nestjs/swagger@3.*
, note the following breaking/API changes in version 4.0.
The following decorators have been changed/renamed:
@ApiModelProperty
is now@ApiProperty
@ApiModelPropertyOptional
is now@ApiPropertyOptional
@ApiResponseModelProperty
is now@ApiResponseProperty
@ApiImplicitQuery
is now@ApiQuery
@ApiImplicitParam
is now@ApiParam
@ApiImplicitBody
is now@ApiBody
@ApiImplicitHeader
is now@ApiHeader
@ApiOperation({ title: 'test' })
is now@ApiOperation({ summary: 'test' })
@ApiUseTags
is now@ApiTags
DocumentBuilder
breaking changes (updated method signatures):
addTag
addBearerAuth
addOAuth2
setContactEmail
is nowsetContact
setHost
has been removedsetSchemes
has been removed
The following methods have been added:
addServer
addApiKey
addBasicAuth
addSecurity
addSecurityRequirements
Example#
A working example is available here.