Replace @nestjs/swagger's Default UI
@nestjs/swagger reads your controllers’ decorators (@ApiTags, @ApiProperty, and the rest) and
builds a complete OpenAPI document at boot time — SwaggerModule.setup() is what then serves that
document through Swagger UI. The document-building half is the useful part; the UI half is what this
guide replaces.
Generate the document as usual
Nothing changes about how the document itself gets built:
const config = new DocumentBuilder()
.setTitle('My API')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
Stop calling SwaggerModule.setup(), expose the JSON directly
SwaggerModule.setup('api', app, document) is what mounts Swagger UI — remove that call (or leave it
under a path you no longer link to), and expose the raw document yourself instead:
app.getHttpAdapter().get('/openapi.json', (req, res) => res.json(document));
This works because Nest’s default platform is Express under the hood, so getHttpAdapter() gives you the
same get() you’d use directly in Express.
Serve GetMan at your docs route
Add one more route that returns GetMan’s page instead of Swagger UI’s:
app.getHttpAdapter().get('/api-docs', (req, res) => {
res.type('html').send(`
<div id="api-docs" style="height: 100vh"></div>
<script src="https://cdn.getman.dev/latest/getman-ui.js"></script>
<script>
GetMan.launch(document.getElementById('api-docs'), { url: '/openapi.json' });
</script>
`);
});
Register both routes in main.ts before app.listen(), the same place SwaggerModule.setup() would
normally go. Everything upstream of the document — decorators, DocumentBuilder config, module
structure — stays exactly as it was.
See the Swagger UI alternative comparison for the feature differences this swap buys you beyond just the routing change above.
Try it with your own spec
Paste any OpenAPI or Swagger URL and see it rendered live — no signup, no install.
Open the explorer