Config files

Configure React Doctor with a doctor.config.* file or the reactDoctor key in package.json. This page explains where React Doctor looks, which config wins, and how each common option changes a scan.

Where React Doctor looks

React Doctor starts in the scanned directory and walks up until it reaches .git or a monorepo root. Put doctor.config.ts or doctor.config.json next to the project you want to scan. You can also put the same object under reactDoctor in package.json.

Use one config per directory. If more than one exists, React Doctor uses the first valid config it finds and ignores lower-priority fallbacks. Local config wins over ancestor config.

JSON config files use JSON5, so comments and trailing commas are allowed. Add $schema: "https://react.doctor/schema/config.json" for editor autocomplete.

Command-line flags override config values.

Example config file

// doctor.config.ts
import { defineConfig } from "react-doctor/api";

export default defineConfig({
  ignore: {
    rules: ["react-doctor/no-danger"],
    files: ["src/generated/**"],
    overrides: [
      {
        files: ["components/search/HighlightedSnippet.tsx"],
        rules: ["react-doctor/no-danger"],
      },
    ],
  },
  rules: {
    "react-doctor/no-array-index-as-key": "error",
  },
  categories: {
    Maintainability: "warn",
  },
});

Use doctor.config.json for JSON config:

{
  "$schema": "https://react.doctor/schema/config.json",
  "ignore": {
    "rules": ["react-doctor/no-danger"],
    "files": ["src/generated/**"],
    "overrides": [
      {
        "files": ["components/search/HighlightedSnippet.tsx"],
        "rules": ["react-doctor/no-danger"]
      }
    ]
  },
  "rules": {
    "react-doctor/no-array-index-as-key": "error"
  },
  "categories": {
    "Maintainability": "warn"
  }
}

Common keys

Use these keys to control scan scope, rule severity, output surfaces, and project-specific escape hatches.

KeyTypeDefaultPurpose
ignore.rulesstring[][]Drop matching rule diagnostics after linting
ignore.filesstring[][]Exclude matching files from scanning
ignore.overrides{ files, rules? }[][]Drop diagnostics for matching files or rules
lintbooleantrueEnable lint diagnostics
deadCodebooleantrueRun dead-code analysis (skipped in diff and staged modes)
warningsbooleantrueSurface warning-severity diagnostics
verbosebooleanfalseShow more detail
diffboolean | stringScan only changed files
blocking"error" | "warning" | "none"errorSeverity that fails CI (exits non-zero)
customRulesOnlybooleanfalseRun only configured custom rules
sharebooleantrueEnable share URL behavior
noScorebooleanfalseSkip the score API
textComponentsstring[][]React Native text component aliases
rawTextWrapperComponentsstring[][]React Native string wrapper components
serverAuthFunctionNamesstring[][]Accepted server auth guard names
respectInlineDisablesbooleantrueRespect inline lint disables
adoptExistingLintConfigbooleantrueMerge existing JSON lint config
rootDirstringScan a different directory, resolved relative to the config file
ignore.tagsstring[][]Disable rule families by tag before linting
rulesobject

Set rule severity to error, warn, or off

categoriesobject

Set category severity to error, warn, or off

bucketsobject

Set severity for curated buckets such as compiler-cleanup

surfacesobjectControl visibility on CLI, score, PR comments, and CI failure
pluginsstring[][]Load custom oxlint-shaped rule plugins

Severity overrides use error, warn, or off. Per-rule rules entries win over categories; buckets currently supports compiler-cleanup for React Compiler cleanup rules.

Category overrides use the five buckets: Security, Bugs, Performance, Accessibility, and Maintainability.

Use rules or categories when you want to change severity or stop a rule from running. Use ignore.rules when you want the rule to run but drop its diagnostics from the final report. Use surfaces when you want a diagnostic to stay visible locally but disappear from PR comments, the score, or the CI failure gate.

React Native escape hatches

Use textComponents for components that behave like React Native's <Text>:

{
  "textComponents": ["Typography", "NativeTabs.Trigger.Label"]
}

Use rawTextWrapperComponents for components that route string children through an internal text component:

{
  "rawTextWrapperComponents": ["Button"]
}

Server auth guards

Use serverAuthFunctionNames when your server actions use custom auth helpers:

{
  "serverAuthFunctionNames": ["requireWorkspaceMember", "ensureSignedIn"]
}

Existing lint config

React Doctor can adopt JSON ESLint and oxlint config automatically. Set adoptExistingLintConfig: false if you want React Doctor to ignore existing lint config.

Narrow ignores and suppressions

Use the narrowest control that solves the problem. Ignore a rule everywhere only when it does not apply to your project:

{
  "ignore": {
    "rules": ["react-doctor/no-danger"]
  }
}

Ignore generated files when every diagnostic in those files is noise:

{
  "ignore": {
    "files": ["src/generated/**"]
  }
}

Ignore one rule in specific files when the exception is local:

{
  "ignore": {
    "overrides": [
      {
        "files": ["components/search/HighlightedSnippet.tsx"],
        "rules": ["react-doctor/no-danger"]
      }
    ]
  }
}

Use an inline suppression when the exception should live with the code:

// react-doctor-disable-next-line react-doctor/no-derived-state-effect
useEffect(() => {
  setValue(initialValue);
}, []);

Comma-separate rule names when one line needs more than one suppression. Use npx react-doctor@latest why src/App.tsx:42 when a suppression does not apply.

Custom rule plugins

React Doctor can run custom oxlint-shaped plugins from your config. Use this for team-specific conventions that do not belong in the core rule set:

{
  "plugins": ["./lint/team-conventions.cjs"],
  "rules": {
    "team-conventions/no-bare-fetch": "error"
  }
}

Plugins export meta and rules:

module.exports = {
  meta: {
    name: "team-conventions",
  },
  rules: {
    "no-bare-fetch": {
      create(context) {
        return {};
      },
    },
  },
};

Rule keys use <plugin-name>/<rule-name>. Plugin rules are opt-in and use the same CLI, score, PR comment, and CI surfaces as built-in rules.