nestjs-doctorGitHub

Configuration

Configuration is optional. nestjs-doctor applies reasonable defaults when no configuration file is present.

Config File

Create nestjs-doctor.config.json in your project root:

{
  "minScore": 75,
  "ignore": {
    "rules": ["architecture/no-orm-in-services"],
    "files": ["src/generated/**"]
  },
  "rules": {
    "architecture/no-barrel-export-internals": false
  },
  "categories": {
    "performance": false
  }
}

Or use a "nestjs-doctor" key in package.json:

{
  "nestjs-doctor": {
    "minScore": 75,
    "rules": {
      "architecture/no-barrel-export-internals": false
    }
  }
}

Config Resolution

The config loader searches for configuration in this order:

  1. Explicit path via --config flag
  2. nestjs-doctor.config.json in the project root
  3. .nestjs-doctor.json in the project root
  4. "nestjs-doctor" key in package.json
  5. Built-in defaults

The first match takes precedence. See Config Loading for implementation details.

Options

KeyTypeDescription
includestring[]Glob patterns to scan (default: ["**/*.ts"])
excludestring[]Glob patterns to skip (additive with defaults)
minScorenumberMinimum passing score (0-100)
ignore.rulesstring[]Rule IDs to suppress
ignore.filesstring[]Glob patterns for files whose diagnostics are hidden
rulesRecord<string, RuleOverride | boolean>Enable/disable individual rules, or override severity
categoriesRecord<string, boolean>Enable/disable entire categories
customRulesDirstringPath to a directory of custom .ts rule files

Rules can be set to false to disable them, or configured with an object to override severity:

{
  "rules": {
    "architecture/no-barrel-export-internals": false,
    "security/no-hardcoded-secret": { "enabled": true, "severity": "error" }
  }
}

Rule objects can also include rule-specific options. Example for no-manual-instantiation:

{
  "rules": {
    "architecture/no-manual-instantiation": {
      "excludeClasses": ["Logger", "PinoLogger"]
    }
  }
}

Some rules accept options under a nested options key. Example for no-circular-module-deps, which can opt out of cycles whose every consecutive edge is wrapped in forwardRef():

{
  "rules": {
    "architecture/no-circular-module-deps": {
      "options": { "ignoreForwardRefCycles": true }
    }
  }
}

Inline Suppression

For one-off exceptions that don't belong in the config file, suppress a rule directly in the source with an ignore comment (disable works as an alias):

const config = eval(raw); // nestjs-doctor-ignore security/no-eval

// nestjs-doctor-ignore-next-line security/no-eval
const config = eval(raw);

// nestjs-doctor-ignore-file security/no-eval
DirectiveScope
nestjs-doctor-ignore[-line] <rules>The comment's own line
nestjs-doctor-ignore-next-line <rules>The line below the comment
nestjs-doctor-ignore-file <rules>Every line in the file

disable works everywhere ignore does. The rule list is space- or comma-separated; omit it to suppress every rule for that scope. A -- reason trailer (placed after the rules) is ignored, so you can document the exception inline. A directive only counts inside a real comment — one that merely appears inside a string literal is ignored.

Inline suppression runs after config-based filtering, so the two mechanisms compose. Line-scoped directives (-line / -next-line) match only code diagnostics. Schema diagnostics (schema/*) have no line and are suppressed only by nestjs-doctor-ignore-file — placed in the entity source for TypeORM/MikroORM/Drizzle, or directly in schema.prisma for Prisma:

// nestjs-doctor-ignore-file schema/require-timestamps

See Diagnostic Filtering for details.

Default Excludes

These patterns are always excluded (your exclude config is additive):

  • node_modules/**, dist/**, build/**, coverage/**
  • **/*.spec.ts, **/*.test.ts, **/*.e2e-spec.ts, **/*.e2e-test.ts
  • **/*.d.ts
  • **/test/**, **/tests/**, **/__tests__/**
  • **/__mocks__/**, **/__fixtures__/**, **/mock/**, **/mocks/**, **/*.mock.ts
  • **/seeder/**, **/seeders/**, **/*.seed.ts, **/*.seeder.ts

Include vs Exclude Behavior

  • exclude patterns are additive to defaults. Your patterns are appended, so safety exclusions like node_modules are never accidentally removed.
  • include patterns replace defaults entirely. If you set include, only those patterns are scanned.

Monorepo Support

Monorepo mode is auto-detected using five strategies (checked in priority order — first match wins):

1. nest-cli.json (takes precedence)

{
  "monorepo": true,
  "projects": {
    "api": { "root": "apps/api" },
    "admin": { "root": "apps/admin" },
    "shared": { "root": "libs/shared" }
  }
}

2. pnpm-workspace.yaml (pnpm / Turborepo)

packages:
  - "apps/*"
  - "packages/*"

3. package.json workspaces (npm / Yarn)

Both array and object formats are supported. Skipped when pnpm-workspace.yaml exists.

{
  "workspaces": ["apps/*", "packages/*"]
}

4. nx.json (Nx)

Discovers sub-projects by scanning for project.json files alongside nx.json.

5. lerna.json (standalone Lerna)

Used when useWorkspaces is not set. Defaults to ["packages/*"] if no packages globs are specified. When useWorkspaces is true, detection falls through to strategy 3.

{
  "packages": ["packages/*"]
}

Non-NestJS packages are always filtered out — only packages with @nestjs/core or @nestjs/common are included. If a monorepo is detected but no NestJS packages are found, nestjs-doctor emits a warning and falls back to single-project mode.

Each sub-project is scanned independently. Per-project config files are supported — place a nestjs-doctor.config.json inside a sub-project's root to override the root config for that project.

The report shows a combined score plus a per-project breakdown.

Scoring

Scores are weighted by severity and category, normalized by file count:

SeverityWeightCategoryMultiplier
error3.0security1.5x
warning1.5correctness1.3x
info0.5schema1.1x
architecture1.0x
performance0.8x
ScoreLabel
90-100Excellent
75-89Good
50-74Fair
25-49Poor
0-24Critical

See Scoring for the full formula and calibration details.