DocTreen

Configuration

All adapters accept the same config object.

{
  docsPath:  '/docs',          // URL where the docs UI is served
  enabled:   true,             // Set false to disable; defaults to NODE_ENV !== 'production'
  liveReload: false,           // Re-discover routes on every docs hit
  meta: {
    title:       'My API',
    version:     '1.0.0',
    description: 'Full description shown in the UI header',
  },
  exclude:   ['/health', /^\/internal\/.*/],  // Paths to hide from docs
  groups: {                    // Group routes under named sections in the sidebar
    Users:    ['/users', '/users/:id'],
    Products: '/products',
  },
  flows:     [...],            // Inline flow presets (see Request Flows)
  flowsPath: './doctreen-flows',  // Directory of *.json flow files
}

Reference

OptionTypeDefaultDescription
docsPathstring'/docs'URL where the docs UI is served
enabledbooleanNODE_ENV !== 'production'Set to false to disable docs entirely
liveReloadbooleanfalseRe-discover routes on every docs request
meta.titlestring'API Documentation'Title shown in the UI header
meta.versionstring'1.0.0'Version label
meta.descriptionstring''Description shown below the title
excludestring | RegExp | Array[]Routes to hide from the docs
groupsRecord<string, string | string[]>{}Group routes into named sidebar sections
flowsFlowDefinition[]nullInline request-flow presets
flowsPathstringauto-detectedDirectory of *.json flow files
validateboolean | ValidateConfigfalseRun runtime validation on every Zod-declared route
defaultErrorsRecord<number, string | { description?, schema? }>{}Default error responses merged into every route (v1.15+)
driftboolean | DriftConfigenv-dependentEnable schema drift detection
openapiOpenAPIConfig{}Tags, servers, security schemes, callbacks/webhooks for the OpenAPI export
headHtmlstring''Inject custom <head> HTML (analytics, favicons, OG tags)

Disabling in production

By default enabled is false when NODE_ENV === 'production'. To serve docs in production, set it explicitly:

expressAdapter(app, { enabled: true, meta: { title: 'My API', version: '1.0.0' } });

Excluding routes

exclude accepts strings, regexes, or arrays of either:

expressAdapter(app, {
  exclude: [
    '/health',
    '/metrics',
    /^\/internal\/.*/,
  ],
});

For per-route control while keeping the route reachable, use hidden: true on defineRoute / @DocRoute instead.

Validation options v1.15

validate accepts a boolean or an object for finer control:

validate: boolean | {
  enabled?:   boolean;               // Run validation (default when object form is used)
  writeback?: boolean;               // Write the parsed payload back onto the request
  response?:  'off' | 'warn' | 'throw';  // Dev-mode response assertion (default 'off')
}
  • validate: true is shorthand for { enabled: true } — validate the request, but don't mutate it (legacy behavior).
  • writeback: true writes the parsed (coerced and defaulted) payload back onto the request, so your handler sees the cleaned values.
  • response: 'warn' | 'throw' asserts handler responses against their declared schema in development.

See runtime validation for the full behavior.

Default error responses v1.15

defaultErrors declares error responses applied to every route, keyed by HTTP status — the same shape as a route's errors. It kills the boilerplate of repeating 401 / 403 / 422 on every defineRoute. Each route's own errors win on a status conflict.

expressAdapter(app, {
  defaultErrors: {
    401: 'Authentication required',
    403: 'Forbidden',
    422: { description: 'Validation failed', schema: s.object({ error: s.string() }) },
  },
});

On this page