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

Inside your Nest app

Serve the static docs build from the NestJS server you already deploy, with private docs and Ask AI included.

Your Nest app can serve the docs itself. One mountOrbitDocs call in main.ts serves the static build under a path such as /docs. It also enforces private docs and answers Ask AI and MCP, so you get every feature without a second server.

Serve the docs at /docs

Match the base path. The site must be built for the path Nest serves it on:

docs/orbitdocs.config.ts
output: { mode: 'static', basePath: '/docs' },

Install the package in the Nest app:

npm install @orbitdocs/nestjs

Mount the build in main.ts, before app.listen():

src/main.ts
import { existsSync } from 'node:fs';
import { join } from 'node:path';

import { NestFactory } from '@nestjs/core';
import { mountOrbitDocs } from '@orbitdocs/nestjs';

import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // dist/main.js → ../docs/out
  const docs = join(__dirname, '../docs/out');
  if (existsSync(docs)) mountOrbitDocs(app, { root: docs, path: '/docs' });

  await app.listen(3000);
}
void bootstrap();

The existsSync check lets the API start before the docs are built.

Build the docs, then start the API:

(cd docs && npx orbitdocs build)
npm run build && npm start

Open http://localhost:3000/docs/.

npx orbitdocs deploy --target nest builds the docs and prints the exact mountOrbitDocs line for your folder layout.

mountOrbitDocs options

mountOrbitDocs(app: INestApplication, options: MountOrbitDocsOptions): void
OptionTypeDefaultWhat it does
rootstringrequiredFolder with the static build (docs/out).
pathstring'/docs'URL path to serve under. Must equal output.basePath.
spec{ file: string; path: string }noneAlso serves a spec file as JSON at path.
authfalse | { publicUrl?: string; env?: Record<string, string | undefined> }on when the build has accessfalse turns private docs off. publicUrl is the docs origin behind a proxy. env replaces process.env as the source of secrets.
aifalse | { env?: Record<string, string | undefined>; rateLimit?: number }on when the build has aifalse turns Ask AI and MCP off. rateLimit is questions per IP per 10 minutes (default 30).

For every request under path, in order: the internal manifests return 404, Ask AI and sign-in routes answer, the access gate runs, then the file is served. Missing files get the site's 404.html.

Express only

mountOrbitDocs supports the Express adapter (@nestjs/platform-express). On Fastify it throws mountOrbitDocs supports the Express adapter in this version. Deploy the docs to a static host or in server mode instead.

Ship the docs with the API

The docs build is a folder, so it travels with your app. In a Docker image, build both and copy docs/out next to dist:

Dockerfile
FROM node:22-bookworm-slim AS build
WORKDIR /app
COPY . .
RUN npm ci && npm ci --prefix docs
RUN cd docs && npx orbitdocs build

FROM node:22-bookworm-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
COPY --from=build /app/docs/out ./docs/out
CMD ["node", "dist/main.js"]
.dockerignore
node_modules
docs/node_modules

orbitdocs build compiles the Nest app (the build command in the config) and extracts the spec, so the build stage needs both installs.

Secrets

Private docs and Ask AI read their secrets from the Nest process environment:

VariableNeeded for
ORBITDOCS_AUTH_SECRET (or access.session.secretEnv)Reader sessions. 32 or more characters.
Each provider's clientSecretEnvSSO sign-in.
ai.apiKeyEnvAsk AI and MCP.

See Environment variables for the full list.

Gotchas

  • Run Nest from the project root. mountOrbitDocs loads express from process.cwd(), so the working directory must be the app that has express installed.
  • Path and base path must match. A build for /docs served at /help loads no CSS or scripts.
  • Global prefix. app.setGlobalPrefix('api') does not apply to mountOrbitDocs; the docs stay at path.

Next steps

Last updated on

On this page