nestrs-openapi discovers all routes registered through #[routes] and impl_routes!, builds an OpenAPI 3.1 document, and serves it at GET /openapi.json. A Swagger UI page is available at GET /docs. You enable the whole thing with a single method call on NestApplication — no separate server, no build step.
What is generated automatically
Step-by-step setup
1
Enable the feature
Add the
openapi feature to your nestrs dependency, or add nestrs-openapi directly if you need the standalone router.2
Call enable_openapi() before listen
Chain Your API is now self-documenting. Open
enable_openapi() on the NestApplication returned by NestFactory::create. This registers GET /openapi.json and GET /docs on the same router as your API.http://localhost:3000/docs in a browser to see the Swagger UI.3
Annotate routes with #[openapi]
Enrich individual handlers with a custom summary, tag, or response codes. Handlers without annotations get sensible defaults.
Customize with OpenApiOptions
When you need to set the API title, version, server URLs, or security schemes, replaceenable_openapi() with enable_openapi_with_options(OpenApiOptions { ... }).
OpenApiOptions have defaults — use ..Default::default() and override only what you need.
Add schemas to components
Schemas are not inferred from handler signatures — the#[openapi(responses = ...)] attribute on handlers sets status codes and descriptions but never content or $ref links. However, Rust types do generate schemas: every #[dto] struct derives schemars::JsonSchema in the same decorator that gives it serde and validator derives. Feed those schemas to nestrs-openapi with two helpers:
schema_entry::<T>("T")— builds one(name, schema)pair from anyJsonSchematype (theschemars::schema_for!output, serialized as JSON Schema).OpenApiOptions::with_schemas([...])— merges those entries intocomponents.schemas.
components.schemas values are JSON Schema documents, so the reflected schema drops in unchanged — including #[serde(rename)] renames and nested #[dto] fields (which arrive as $ref + $defs chains).
Because the
#[dto] derive expansion references the schemars (and validator) crate paths directly, your crate needs schemars = "1" as a direct dependency. nestrs re-exports it as nestrs::schemars.schema_entry / with_schemas populate components.schemas for tooling, codegen, and client generation; attaching content.application/json.schema.$ref to specific operations is on you (post-process the JSON, or merge external fragments as below).
For types outside #[dto], or schemas you want to author by hand, pass them under OpenApiOptions.components:
Global security scheme
Declare a security scheme undercomponents.securitySchemes and reference it in the root security array to apply it to all operations in the Swagger UI.
Per-route security from #[roles]
When handlers use#[roles("admin")], the macro stores roles metadata in MetadataRegistry. Setting infer_route_security_from_roles: true tells nestrs-openapi to add a security array to those operations automatically, so Swagger UI shows a lock icon only on protected routes.
#[roles("admin")] get "security": [{ "bearerAuth": [] }] in the generated document. Routes without #[roles] are left unchanged.
Standalone router
If you manage your own Axum router rather than usingNestApplication, import openapi_router from nestrs-openapi directly and merge the returned Router into your app.
api_prefix so the documented paths in openapi.json match the actual URLs your application serves.