OrbitDocs packages are coming to npm soon. Until then, run it from the GitHub repo →
NestJS

NestJS

Install the Nest integration, point the docs at your app and choose which routes appear.

@orbitdocs/nestjs connects your Nest app to the docs. It builds on @nestjs/swagger: extraction calls your app's own SwaggerModule.createDocument. Everything you already describe with Swagger shows up in the docs. The @Docs* decorators are optional extras on top.

There is no Nest module to import and nothing changes at runtime. The package gives you decorators, the extractor the CLI runs, and mountOrbitDocs to serve the built site.

What's in this section

Install

Add the packages to your Nest project

npm install @orbitdocs/nestjs @nestjs/swagger

@orbitdocs/nestjs needs @nestjs/common and @nestjs/core 10 or later, @nestjs/swagger 7 or later, and reflect-metadata. Install it in the Nest project, not in the docs app: the extractor is loaded from there so it shares your copy of Nest.

Turn on the Swagger CLI plugin

nest-cli.json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "@nestjs/swagger",
        "options": { "introspectComments": true, "classValidatorShim": true }
      }
    ]
  }
}

With the plugin, DTO property types become schemas without @ApiProperty. With introspectComments, JSDoc comments become descriptions and @example tags become examples:

src/bookings/booking.dto.ts
export class PassengerDto {
  /**
   * Full name as on the travel document.
   * @example "Ada Lovelace"
   */
  @IsString()
  name: string;
}

Create the docs app

npx orbitdocs init

This writes docs/ with a config that points at your compiled module. See Quickstart for the full walkthrough.

Point the docs at your app

Each API in orbitdocs.config.ts has a source. For a Nest app it is source.nest:

docs/orbitdocs.config.ts
import { defineConfig } from '@orbitdocs/next/config';

export default defineConfig({
  site: { title: 'Orbit Travel' },
  apis: [
    {
      id: 'travel',
      title: 'Orbit Travel API',
      source: {
        nest: {
          module: 'dist/app.module.js',
          build: 'nest build',
          routes: 'opt-in',
          versioning: { type: 'uri', prefix: 'v' },
        },
      },
    },
  ],
});

Prop

Type

Extraction explains each option with examples.

Choose which routes appear

routes decides which of your routes reach the docs. Both modes use the same Swagger metadata.

Only routes marked with @DocsOperation appear. Health checks, admin routes and internal hooks stay out until you mark them. Choose this when the API serves more than your public clients.

src/flights/flights.controller.ts
@Get()
@DocsOperation({ group: 'Flights', title: 'Search flights', order: 1 })
search(@Query() query: SearchFlightsQueryDto): FlightListDto {
  // ...
}

@Get('internal/stats') // not marked: never in the docs
stats() {}

In both modes:

  • @ApiOperation({ summary }) gives the title, and @ApiTags the sidebar group, unless @DocsOperation sets title or group.
  • The title also becomes the operation's URL slug: Create a booking becomes /reference/travel/create-a-booking/.
  • @DocsOperation still adds order and stability, and @DocsErrors, @DocsSamples and @DocsContent work on any route.

Give every route a title in 'all' mode

A route without @ApiOperation({ summary }) or a title is named after Nest's operation id, such as BookingsController_create. Its URL becomes /reference/travel/bookingscontroller-create/.

What drives the docs

Everything @nestjs/swagger understands is used. Common ones:

Swagger featureShows up as
DTO classes and the CLI pluginRequest and response schemas, with types, enums, formats and limits
@ApiProperty({ description, example }), JSDoc and @exampleField descriptions and examples in samples
@ApiOperation({ summary, description })Operation title and description
@ApiTags('Bookings')Sidebar group
@ApiParam, @ApiQuery, @ApiHeaderParameters, with descriptions and examples
@ApiBody, @ApiConsumes('multipart/form-data')Request body and media type
@ApiResponse, @ApiOkResponse, …Responses and their schemas
@ApiExtraModels()Schemas referenced only through getSchemaPath()
@ApiExcludeEndpoint(), @ApiExcludeController()Routes kept out
@ApiBearerAuth(), @ApiSecurity()Which routes need auth. Declare the schemes themselves in the config: see Authentication.

OrbitDocs then adds what your routes return by construction: 400 when a route takes input, 401 and 403 when it is secured, 404 when its path has a parameter, and 500. Turn this off with standardErrors: false on the API. See Extraction.

Environment variables

OrbitDocs reads secrets from environment variables. The config only names them, so no secret is ever written to orbitdocs.config.ts or the build.

WhenVariableRequiredWhat it does
ExtractionAny variable your app reads while its modules loadIf your app needs itSet placeholders with source.nest.env. Real values in the shell win. See Extraction.
Serving from Nest, with accessORBITDOCS_AUTH_SECRET (the name in access.session.secretEnv)YesSigns reader sessions. At least 32 characters.
Serving from Nest, with accessEach clientSecretEnv of access.providersYes, per providerThe OAuth client secret of that sign-in provider.
Serving from Nest, with accessaccess.personalization.secretEnv, appSession.jwtSecretEnv, appSession.secretKeyEnvWhen you use that optionPersonalization hook signing, a Supabase legacy JWT secret, a Clerk secret key.
Serving from Nest, with aiThe name in ai.apiKeyEnvYesYour LLM provider's API key for Ask AI.

The serving variables are read by the Nest process at runtime, not by the build. Serve from Nest explains each one. examples/nest-sample/.env.example in the repository shows a complete set, and Environment variables lists every variable OrbitDocs uses.

Output mode is not an environment variable

OrbitDocs reads output.mode from the config only. The sample app's config picks it from its own ORBITDOCS_MODE variable, which you can copy: mode: process.env.ORBITDOCS_MODE === 'server' ? 'server' : 'static'.

Next steps

Last updated on

On this page