Skip to main content

vipr.config.json Schema

Vipr works without a config file. When you add one, it gives you a persistent place to set output defaults, enforce quality thresholds, tune per-analyzer behavior, and express environment-specific overrides for CI. This page documents every supported field.

Location and discovery

Vipr walks up from the current working directory looking for vipr.config.json. Place it at your project root alongside package.json.

# Point at a specific file
vipr analyze src/ --config ./config/vipr.config.json

# Skip config loading entirely
vipr analyze src/ --no-config

CLI flags always override config file values. Config file values override built-in defaults.

Minimal example

{
  "$schema": "https://vipr.dev/schemas/vipr-config.schema.json",
  "output": {
    "failThreshold": 70,
    "failOnCritical": true
  }
}

Full structure

{
  "$schema": "https://vipr.dev/schemas/vipr-config.schema.json",
  "extends": "./base.config.json",
  "global": { ... },
  "output": { ... },
  "plugins": { ... },
  "analyses": { ... },
  "env": { ... }
}

global

Cross-cutting settings that apply before any analyzer runs.

Key Type Default Description
global.debug boolean false Print debug-level logs during analysis
global.cache boolean true Enable in-memory result caching
global.cacheTTL number 3600000 Cache time-to-live in milliseconds
global.ignorePatterns string[] Built-in list Additional paths and glob patterns to exclude
global.gradeBoundaries object See below Complexity score cutoffs for grade letters

Default ignore patterns

The built-in ignore list covers: node_modules, .git, dist, build, .next, coverage, .turbo, out, .vite, __mocks__, mock, mocks, __tests__, fixtures, docs, public, generated. Files matching *.test.*, *.spec.*, *.stories.*, *.d.ts, and *.json are also excluded automatically.

Use ignorePatterns to extend — not replace — that list:

{
  "global": {
    "ignorePatterns": ["scripts/**", "e2e/**", "**/*.generated.ts"]
  }
}

gradeBoundaries

Maps the 0–100 quality score to letter grades. Lower raw score = worse quality. The defaults:

{
  "global": {
    "gradeBoundaries": {
      "A": 25,
      "B": 45,
      "C": 65,
      "D": 80
    }
  }
}

A score below the A boundary receives an A grade; between A and B boundaries receives B; and so on. A score above D receives an F. The strict preset tightens these boundaries.

output

Controls how results are formatted and when the command exits non-zero.

Key Type Default Description
output.format cli | json | json-full | markdown cli Default output format
output.minSeverity info | warning | critical info Lowest severity level shown
output.failThreshold number 0 Exit non-zero when any file scores below this (0–100)
output.failOnCritical boolean false Exit non-zero when any critical-severity finding is present
output.compact boolean false Minify JSON output (no whitespace)

Setting failThreshold to 0 disables the score gate. Setting failOnCritical to true is the most common CI configuration — it fails only when Vipr finds something it classifies as immediately actionable.

plugins

Per-analyzer configuration keyed by plugin ID. Each plugin owns its own threshold and weight schema. Unrecognized keys are silently ignored.

{
  "plugins": {
    "core": { ... },
    "react": { ... }
  }
}

plugins.core

The core plugin scores every JS/TS file on cyclomatic complexity, cognitive complexity, Halstead metrics, maintainability index, and lines of code.

{
  "plugins": {
    "core": {
      "id": "core",
      "thresholds": {
        "cyclomaticComplexity": 10,
        "cognitiveComplexity": 15,
        "halsteadVolume": 1000,
        "halsteadDifficulty": 30,
        "linesOfCode": 250
      },
      "weights": {
        "complexity": {
          "cyclomatic": 0.3,
          "cognitive": 0.3,
          "halstead": 0.2,
          "linesOfCode": 0.2
        }
      }
    }
  }
}

Core thresholds — all are single numbers; files that exceed the threshold receive a warning:

Key Default What it measures
cyclomaticComplexity 10 Number of independent paths through a function
cognitiveComplexity 15 How hard a function is to understand (nested conditionals cost more)
halsteadVolume 1000 Estimated program size in bits based on operators and operands
halsteadDifficulty 30 Effort required to write or understand the code
linesOfCode 250 Raw line count (physical lines, not logical statements)

Core complexity weights — must sum to 1.0. Changing these shifts how the composite score is calculated across the four complexity dimensions:

Key Default Role
cyclomatic 0.3 Weight for cyclomatic complexity dimension
cognitive 0.3 Weight for cognitive complexity dimension
halstead 0.2 Weight for Halstead dimension
linesOfCode 0.2 Weight for lines-of-code dimension

plugins.react

The React plugin analyzes .tsx and .jsx files for structural complexity, hook usage, temporal coupling (effects), prop coupling, component identity, dataflow, anti-patterns, security, accessibility, performance, reliability, and technical debt.

The React plugin config surface that is stable for user overrides:

{
  "plugins": {
    "react": {
      "id": "react",
      "thresholds": {
        "structural": {
          "warning": 15
        },
        "hooks": {
          "total": 10,
          "customHookSuggestion": 8
        },
        "coupling": {
          "propsWarning": 10,
          "contextWarning": 3
        }
      }
    }
  }
}

React structural thresholds:

Key Default Description
structural.warning 15 Structural complexity score at which a warning is raised

React hook thresholds:

Key Default Description
hooks.total 10 Total hook calls before a warning
hooks.customHookSuggestion 8 Hook count above which extracting a custom hook is suggested
hooks.stateCountWarning 3 useState calls per component before warning
hooks.effectCountWarning 2 useEffect calls per component before warning

React coupling thresholds:

Key Default Description
coupling.propsWarning 10 Prop count before a coupling warning
coupling.contextWarning 3 Context consumers before a warning
coupling.propsDrillingThreshold 7 Prop count before prop-drilling detection activates

Note: The weights object on the React plugin config is large and covers many internal scoring dimensions (structural, hooks, temporal, coupling, identity, dataflow, reliability, accessibility, security, anti-pattern). These fields are read at runtime but are not recommended for routine user override — changing them without understanding the scoring model will produce unexpected results. Stick to thresholds for day-to-day tuning.

analyses

Enable or disable individual named analyses without touching plugin-level thresholds.

{
  "analyses": {
    "core-dead-code": { "enabled": false },
    "react-migration": { "enabled": false }
  }
}

Analysis IDs follow the pattern <plugin>-<name>. The full list of built-in analysis IDs:

Plugin Analysis IDs
core core-cyclomatic, core-cognitive, core-halstead, core-maintainability, core-functions, core-dead-code
react react-structural, react-hooks, react-temporal, react-coupling, react-identity, react-dataflow, react-anti-patterns, react-security, react-accessibility, react-performance, react-reliability, react-technical-debt, react-migration

extends

Layer one config on top of another. Relative paths are resolved from the file that declares them.

{
  "extends": "./base.config.json",
  "output": {
    "format": "json"
  }
}

Arrays replace rather than merge when extending. Nested objects merge deeply. You can pass an array to extend multiple configs in order:

{
  "extends": ["./base.config.json", "./ci.config.json"]
}

env

Override any config section for a named environment. The public CLI does not expose an --env flag today. The env block is still part of the shared config contract for callers that supply an environment name before CLI overrides are applied.

{
  "output": { "format": "cli" },
  "env": {
    "ci": {
      "output": {
        "format": "json",
        "failThreshold": 75,
        "failOnCritical": true
      }
    }
  }
}

Presets

Run vipr init to scaffold a starter config interactively. Use --preset to skip the wizard:

vipr init --preset strict --quiet
Preset failThreshold failOnCritical Grade boundaries Use when
default 60 false Standard (A=25, B=45, C=65, D=80) New projects, legacy codebases
strict 80 true Tighter (A=15, B=30, C=50, D=70) Greenfield projects, high-quality targets
lenient 40 false Looser (A=35, B=55, C=75, D=90) Bootstrapping gates on existing debt

The strict preset also tightens React and core thresholds:

{
  "plugins": {
    "core": {
      "id": "core",
      "thresholds": {
        "cyclomaticComplexity": { "warning": 8, "critical": 15 }
      }
    },
    "react": {
      "id": "react",
      "thresholds": {
        "structural": { "warning": 12 },
        "hooks": { "total": 8, "customHookSuggestion": 6 },
        "coupling": { "propsWarning": 6 }
      }
    }
  }
}

Overriding for test files

The env block does not yet support per-glob overrides in the public CLI. To exclude test files from analysis entirely, use global.ignorePatterns:

{
  "global": {
    "ignorePatterns": ["**/*.test.ts", "**/*.spec.tsx", "**/__tests__/**"]
  }
}

Test files matching .test.* and .spec.* are already excluded by the built-in ignore list.

Note: Per-glob threshold overrides (e.g., applying lenient thresholds to *.test.ts) are not yet supported in vipr.config.json. If this is blocking for you, open an issue — the schema has a placeholder for it.

Documentation