nestjs-doctorGitHub

Setup

Quick Start

Run directly with npx:

npx nestjs-doctor@latest .

For file paths and line numbers:

npx nestjs-doctor@latest . --verbose

No configuration or plugins are required.

Installation

Install as a dev dependency for consistent CI runs:

npm install -D nestjs-doctor

CLI Usage

Usage: nestjs-doctor [directory] [options]

  --verbose       Show file paths and line numbers per diagnostic
  --score         Output only the numeric score (for CI)
  --json          JSON output (for tooling)
  --report        Generate an interactive HTML report (--graph also works)
  --min-score <n> Minimum passing score (0-100). Exits with code 1 if below
  --config <p>    Path to config file
  --init          Set up the /nestjs-doctor skill for AI coding agents
  -h, --help      Show help

CI Integration

Use --min-score to enforce a minimum health score in your CI pipeline:

npx nestjs-doctor . --min-score 75

Or add it as a script in package.json:

{
  "scripts": {
    "health": "nestjs-doctor . --min-score 75"
  }
}

Exit Codes

CodeMeaning
0Score is at or above threshold
1Score is below threshold, or errors were found
2Invalid input (bad path, invalid flags)

All output modes (--score, --json, default) respect exit codes.

Report

npx nestjs-doctor@latest . --report

Self-contained HTML file with four sections: score summary, source-level diagnostics with code viewer, interactive module graph, and a custom rule playground. Opens in your browser.

Module Graph

AI Coding Agents

Ships with skills for popular AI coding agents. Run --init to auto-detect installed agents and install the nestjs-doctor skill for each one:

npm install -D nestjs-doctor
npx nestjs-doctor --init
AgentDetectionSkill location
Claude Code~/.claude exists~/.claude/skills/nestjs-doctor/
Amp Code~/.amp exists~/.config/amp/skills/nestjs-doctor/
Cursor~/.cursor exists~/.cursor/skills/nestjs-doctor/
OpenCodeopencode CLI or ~/.config/opencode~/.config/opencode/skills/nestjs-doctor/
Windsurf~/.codeium existsAppends to ~/.codeium/windsurf/memories/global_rules.md
Antigravityagy CLI or ~/.gemini/antigravity~/.gemini/antigravity/skills/nestjs-doctor/
Gemini CLIgemini CLI or ~/.gemini~/.gemini/skills/nestjs-doctor/
Codexcodex CLI or ~/.codex~/.codex/skills/nestjs-doctor/

A project-level fallback is always written to .agents/nestjs-doctor/. Commit it so every contributor gets the skill automatically.

Skills

--init installs two skills per agent:

SkillCommandDescription
nestjs-doctor/nestjs-doctorRuns the scan, shows the report, and fixes what it can
nestjs-doctor-create-rule/nestjs-doctor-create-ruleScaffolds a custom rule: checks feasibility, writes the .ts file, updates config, verifies it loads

See Custom Rules for the rule format.

Node.js API

nestjs-doctor can be used programmatically:

import { diagnose, diagnoseMonorepo } from "nestjs-doctor";

const result = await diagnose("./my-nestjs-app");
result.score; // { value: 82, label: "Good" }
result.diagnostics; // Diagnostic[]
result.summary; // { total, errors, warnings, info, byCategory }

const mono = await diagnoseMonorepo("./my-monorepo");
mono.isMonorepo; // true
mono.subProjects; // [{ name: "api", result }, ...]
mono.combined; // Merged DiagnoseResult

See the pipeline overview for details on the DiagnoseResult structure.

Incremental Scanning API

For tooling that needs fine-grained control — such as editor integrations and language servers — nestjs-doctor exports an incremental scanning API. Instead of running a full diagnose() call, you can prepare a scan context once and then re-scan individual files as they change.

import {
  prepareScan,
  updateFile,
  scanFile,
  scanAllFiles,
  scanProject,
  updateModuleGraphForFile,
  updateProvidersForFile,
  getRules,
} from "nestjs-doctor";

Lifecycle

// 1. Prepare the scan context (parses all files, builds module graph, resolves providers)
const { context, customRuleWarnings } = await prepareScan("./my-nestjs-app");

// 2. When a file changes, update it in the context
updateFile(context, "/absolute/path/to/changed-file.ts");

// 3. Re-scan just that file (file-scoped rules only)
const { diagnostics, errors } = scanFile(context, "/absolute/path/to/changed-file.ts");

// 4. Or re-run all file-scoped rules across every file
const allFileResults = scanAllFiles(context);

// 5. Or re-run project-scoped rules (module graph, circular deps, etc.)
const projectResults = scanProject(context);

Granular Updates

If you need to update the module graph or providers independently (for example, after editing multiple files before re-scanning):

updateModuleGraphForFile(context.moduleGraph, context.astProject, filePath);
updateProvidersForFile(context.providers, context.astProject, filePath);

Listing Rules

import { getRules } from "nestjs-doctor";

const rules = getRules(); // all built-in rules (AnyRule[])

ScanContext

The prepareScan function returns a ScanContext that holds:

FieldTypeDescription
astProjectProjectts-morph project with all source files
configNestjsDoctorConfigResolved configuration
filesstring[]Collected file paths
fileRulesRule[]File-scoped rules (filtered by config)
projectRulesProjectRule[]Project-scoped rules (filtered by config)
moduleGraphModuleGraphImport/export graph
providersMap<string, ProviderInfo>Resolved NestJS providers
targetPathstringRoot directory of the scanned project