API documentation often feels like a chore. You know you need it, but nobody wants to spend hours writing static docs that quickly go out of date. That’s why I always reach for Swagger when I’m building with NestJS.
With a few lines of code, you get live, interactive API documentation that updates whenever you add new endpoints. It saves you time, makes onboarding new developers easier, and honestly—it just looks professional.
In this tutorial, I’ll walk you through setting up NestJS Swagger step by step. We’ll start small, add useful options, and finish with a documentation page that’s actually pleasant to use.
Installing NestJS Swagger
Let’s start with the basics. NestJS has official support for Swagger through the @nestjs/swagger package. Install it like this:
npm install --save @nestjs/swagger
That’s all it takes to get started with NestJS Swagger.
Quick tip: if you’ve ever accidentally pushed code to the wrong branch, you’ll appreciate our guide on moving a Git commit to another branch. It’s a lifesaver for keeping your project clean.
Setting Up Swagger in main.ts
Here’s the part most tutorials bury halfway down the page—I’ll give it to you upfront. Open your main.ts file and paste this:
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('Library API')
.setDescription('Manage books and authors with ease')
.setVersion('1.0')
.addTag('books')
.addTag('authors')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
Now run your app and open http://localhost:3000/api. You’ll see Swagger UI with your endpoints neatly documented. That’s NestJS Swagger in action
Why “Library API”? Because it’s a relatable example—you can imagine creating and fetching books and authors instead of looking at abstract “Cats” or “Users” that every tutorial seems to use.
Running the App
Starting the app is the same as always:
npm run start
Then visit:
/api→ the Swagger UI/api-json→ the raw OpenAPI JSON
This JSON file is especially useful for client SDK generation or Postman imports—two things that become easier thanks to NestJS Swagger.
If you’ve ever used Git Reset Soft to undo changes without losing them, you’ll recognize a similar principle here: you keep all your work intact, just presented more safely (here’s how Git Reset Soft works).
Making Docs Useful with DTOs
Swagger really shines when you add DTOs (Data Transfer Objects). Instead of showing vague “string” inputs, it can display structured request bodies.
Here’s a CreateBookDto with Swagger decorators:
import { ApiProperty } from '@nestjs/swagger';
export class CreateBookDto {
@ApiProperty({ example: 'The Pragmatic Programmer' })
title: string;
@ApiProperty({ example: 'Andrew Hunt' })
author: string;
}
And in your controller:
import { Body, Controller, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { CreateBookDto } from './dto/create-book.dto';
@ApiTags('books')
@Controller('books')
export class BooksController {
@Post()
create(@Body() dto: CreateBookDto) {
return { message: 'Book created', book: dto };
}
}
Check Swagger again—you’ll see a structured form for creating books. This is the magic of NestJS Swagger: your code doubles as documentation.
This is one of my favorite parts of NestJS Swagger—it turns the DTOs you already have into real documentation without extra work.
This reminds me of working with JSON columns in PostgreSQL, where a structured schema makes queries so much easier. If that’s relevant to your work, check out our guide on querying JSON columns in PostgreSQL.
Adding Authentication in NestJS Swagger
APIs without authentication are rare. Luckily, adding JWT support in Swagger takes just one line:
const config = new DocumentBuilder()
.setTitle('Library API')
.setDescription('Secure API documentation')
.setVersion('1.0')
.addBearerAuth()
.build();
Now your Swagger UI includes an Authorize button. Paste in a JWT once, and every request you try from the docs will automatically include the token.
This has saved me countless hours when testing secured endpoints—I don’t have to juggle curl commands or Postman setups.
Grouping Endpoints with Tags
Tags may seem minor, but they make your docs readable at scale. For example, separating books from authors:
@ApiTags('authors')
@Controller('authors')
export class AuthorsController {
@Get()
findAll() {
return [{ name: 'Harper Lee' }, { name: 'George Orwell' }];
}
}
Swagger now shows two clean groups: Books and Authors. In larger projects, I’ve used tags like users, payments, and reports to help teammates find what they need faster.
If you’re managing multiple stashes in Git, you already know how important organization is. That’s where Git Stash List comes in handy for developers.
Customizing Swagger
If you want more control, NestJS gives you extra options.
Operation IDs
By default, Swagger generates IDs that can get messy. Fix it like this:
import { SwaggerDocumentOptions } from '@nestjs/swagger';
const options: SwaggerDocumentOptions = {
operationIdFactory: (controllerKey: string, methodKey: string) => methodKey,
};
I like this because it keeps operation IDs short and predictable.
Setup Options
For the UI itself, you can enable features like the search bar:
import { ExpressSwaggerCustomOptions } from '@nestjs/swagger';
const setupOptions: ExpressSwaggerCustomOptions = {
explorer: true,
};
SwaggerModule.setup('api', app, document, setupOptions);
If you’ve ever scrolled endlessly through dozens of endpoints, you’ll appreciate how useful that search box is.
If you’ve ever scrolled endlessly through dozens of endpoints, you’ll appreciate how useful that search box is.
For even deeper customization, the NestJS Swagger official docs explain advanced options well.
Why I Recommend NestJS Swagger
I’ve worked on projects with Swagger and without. The difference is huge.
On one team, before Swagger, we had endless Slack messages:
- “What’s the request body for this endpoint again?”
- “Did the response shape change after the last deploy?”
After setting up NestJS Swagger, those questions nearly vanished. The docs became our single source of truth.
For me, Swagger isn’t optional anymore—it’s part of my default setup when starting a NestJS project.
For me, Swagger isn’t optional anymore—it’s part of my default setup when starting a NestJS project. If you want to understand why this works so well at an industry level, the OpenAPI Initiative provides valuable context.
Conclusion
Integrating NestJS Swagger doesn’t take long, but it pays off immediately. You get interactive docs that:
- Update automatically with your code
- Save teammates from asking repetitive questions
- Make your API feel polished and professional
For me, it’s become as essential as writing controllers or services. If you’re starting a new NestJS project, add Swagger from the beginning—you’ll thank yourself later.
Happy coding, and may your APIs always be well-documented!
Leave a Reply