DocfyUiModule.setup(mountPath, app, options?)

Serves docfy-ui (this package's AI-first companion documentation UI) at mountPath — the same role that SwaggerModule.setup() + swagger-ui-express play for the raw Swagger UI.

Usage

Works on both Express (@nestjs/platform-express) and Fastify (@nestjs/platform-fastify) apps. On Fastify, static asset serving needs the optional peer dependency @fastify/static (npm install @fastify/static) — the same package @nestjs/swagger itself relies on for Fastify Swagger UI support.

ts
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { DocfyUiModule } from 'nestjs-docfy';

const app = await NestFactory.create(AppModule);

DocfyUiModule.setup('/docs', app); // before SwaggerModule.setup; see staticSpecPath below

const document = SwaggerModule.createDocument(app, new DocumentBuilder().build());
SwaggerModule.setup('api', app, document); // exposes /api-json, which docfy-ui fetches by default

await app.listen(3000);

Visit /docs: no further configuration is needed, since docfy-ui fetches /api-json same-origin by default.

Options

OptionTypeDefaultDescription
staticSpecPathstringnonePath to a pre-built OpenAPI JSON file, served at /api-json instead of the app's live one.

staticSpecPath (required if your app builds with webpack: true)

The DocfyModule runtime metadata pipeline can't apply docs files there, so the live /api-json will be missing everything docs files would add. Generate a patched document beforehand:

bash
npx nestjs-docfy patch-spec --spec http://localhost:3000/api-json --out openapi.patched.json

And serve it:

ts
DocfyUiModule.setup('/docs', app, { staticSpecPath: './openapi.patched.json' });

Call this before SwaggerModule.setup(): Express resolves routes in registration order, so the patched static document takes precedence over the live one for any request to /api-json. On Fastify, SwaggerModule.setup() registering its own /api-json route alongside this throws FST_ERR_DUPLICATED_ROUTE at startup instead — registration order doesn't help there, so point SwaggerModule.setup() at a different jsonDocumentUrl (or pass { raw: false }) when combining it with staticSpecPath on Fastify.

Caveat: BrowserRouter and mount path

Non-root mount path

docfy-ui renders with React Router's BrowserRouter and no configurable basename yet, so deep client-side routes (for example, refreshing directly on an endpoint's detail page) only resolve correctly when mountPath is / (the application root). Mounting elsewhere (for example, /docs) still serves the UI and the initial load works; in-app navigation to a specific endpoint followed by a refresh of that URL still doesn't work on a non-root mount path.