Migration Guide
Migrate from @nestjs/swagger to nestjs-openapi
Migrate from @nestjs/swagger runtime generation to nestjs-openapi static analysis.
Key Differences
| Aspect | @nestjs/swagger | nestjs-openapi |
|---|---|---|
| When | Runtime (app startup) | Build time (static analysis) |
| Requirements | Running app, infrastructure | Only source code |
| Decorator support | Full (with CLI plugin) | Core decorators |
| Security | Extracted from decorators | Configured in config file |
| Performance | Adds startup time | Zero runtime overhead |
Step 1: Install
npm install -D nestjs-openapiStep 2: Create Configuration
Convert your SwaggerModule.setup() configuration to a config file:
Before: Runtime Setup
// main.ts
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('My API')
.setDescription('API description')
.setVersion('1.0.0')
.addServer('https://api.example.com', 'Production')
.addServer('http://localhost:3000', 'Development')
.addBearerAuth()
.addApiKey({ type: 'apiKey', name: 'X-API-Key', in: 'header' }, 'apiKey')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api-docs', app, document);
await app.listen(3000);
}After: Static Configuration
// openapi.config.ts
import { } from 'nestjs-openapi';
export default ({
: 'openapi.json',
: {
: 'src/app.module.ts',
},
: {
: {
: 'My API',
: 'API description',
: '1.0.0',
},
: [
{ : 'https://api.example.com', : 'Production' },
{ : 'http://localhost:3000', : 'Development' },
],
: {
: [
{
: 'bearerAuth',
: 'http',
: 'bearer',
},
{
: 'apiKey',
: 'apiKey',
: 'header',
: 'X-API-Key',
},
],
: [{ : [] }],
},
},
});Step 3: Generate Spec
npx nestjs-openapi generate -c openapi.config.tsStep 4: Serve at Runtime (Optional)
Replace SwaggerModule.setup() with OpenApiModule:
Before
// main.ts
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api-docs', app, document);After
// app.module.ts
import { OpenApiModule } from 'nestjs-openapi';
@Module({
imports: [
OpenApiModule.forRoot({
filePath: 'openapi.json',
serveSwaggerUi: true,
swaggerUiPath: '/api-docs',
}),
],
})
export class AppModule {}Step 5: Update Build Scripts
Add generation to your build process:
{
"scripts": {
"prebuild": "npx nestjs-openapi generate -c openapi.config.ts",
"build": "nest build"
}
}Or run separately:
{
"scripts": {
"openapi": "nestjs-openapi generate -c openapi.config.ts",
"build": "nest build"
}
}Decorator Migration
Supported Decorators
These decorators work the same way:
// Routing - fully supported
@Controller('users')
@Get(), @Post(), @Put(), @Patch(), @Delete()
@Param(), @Query(), @Body(), @Headers()
@HttpCode()
// Documentation - fully supported
@ApiTags()
@ApiOperation()
@ApiParam(), @ApiQuery(), @ApiBody()
@ApiResponse() // Requires status property
@ApiConsumes(), @ApiProduces()
@ApiProperty(), @ApiPropertyOptional()
@ApiExcludeEndpoint()Security Decorators: Config-Based
Security decorators are supported and work similarly to @nestjs/swagger. Define schemes in config, then use decorators to apply them:
// openapi.config.ts - Define available schemes
openapi: {
security: {
schemes: [
{ name: 'bearerAuth', type: 'http', scheme: 'bearer' },
{ name: 'admin-key', type: 'apiKey', in: 'header', parameterName: 'X-Admin-Key' },
],
// Optional: global requirements for all endpoints
global: [{ bearerAuth: [] }],
},
}
// Controller - Use decorators as usual
@Controller('users')
@ApiBearerAuth() // Applies to all methods
export class UsersController {
@Get('admin')
@ApiSecurity('admin-key') // Method-specific security
getAdmin() {}
}CLI Plugin Features
If you use the NestJS Swagger CLI plugin for automatic type inference, note that nestjs-openapi performs its own static analysis. You can remove the CLI plugin:
// nest-cli.json - remove if using nestjs-openapi
{
"compilerOptions": {
"plugins": ["@nestjs/swagger"] // Can be removed
}
}Common Migration Issues
Issue: Security Decorator Not Appearing in Spec
Problem: @ApiBearerAuth() or other security decorators don't appear in the generated spec.
Solution: Ensure the scheme is defined in config. Decorators reference scheme names that must exist in openapi.security.schemes:
// openapi.config.ts
openapi: {
security: {
schemes: [
{ name: 'bearer', type: 'http', scheme: 'bearer' }, // Default name for @ApiBearerAuth()
{ name: 'jwt', type: 'http', scheme: 'bearer' }, // For @ApiBearerAuth('jwt')
],
},
}Issue: @ApiResponse Without Status
Problem: Responses don't appear in the spec.
Solution: Always include the status property:
// Won't work - missing status
@ApiResponse({ description: 'Success', type: UserDto })
// Works
@ApiResponse({ status: 200, description: 'Success', type: UserDto })Issue: Complex Type Inference
Problem: Some complex types aren't properly inferred.
Solution: Use explicit @ApiProperty decorators:
export class ResponseDto {
@ApiProperty({ type: () => UserDto })
user: UserDto;
@ApiProperty({ type: [String] })
tags: string[];
}Issue: Dynamic Routes
Problem: Routes defined dynamically at runtime can't be analyzed.
Solution: Ensure all routes are defined with decorators in source code. Dynamic route registration isn't supported.
Hybrid Approach
You can run both tools during migration:
// main.ts - Keep @nestjs/swagger for comparison
if (process.env.USE_RUNTIME_SWAGGER === 'true') {
const config = new DocumentBuilder()
.setTitle('My API')
.setVersion('1.0.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('swagger', app, document);
}// app.module.ts - Also use static generation
@Module({
imports: [
OpenApiModule.forRoot({
filePath: 'openapi.json',
serveSwaggerUi: true,
swaggerUiPath: '/docs', // Different path
}),
],
})Compare the outputs at /swagger vs /docs to verify parity.
Checklist
- Install
nestjs-openapi - Create
openapi.config.tswith equivalent settings - Move security configuration from decorators to config
- Add
@ApiResponse({ status: ... })where needed - Run
npx nestjs-openapi generateand validate output - Update build scripts
- (Optional) Replace
SwaggerModule.setupwithOpenApiModule - (Optional) Remove
@nestjs/swaggerCLI plugin from nest-cli.json - Compare generated specs for parity
Benefits After Migration
- Faster CI/CD - No app bootstrap needed
- No infrastructure - Generate specs without database
- Consistent output - Same spec regardless of environment
- Type safety - Config is fully typed
- Git-friendly - Generated spec can be committed and tracked
Next Steps
- Configuration Guide - Full config reference
- Security Guide - Configure authentication
- CI/CD Recipe - Automate generation