| | |

ESLint 16 🛡️ The –fix Flag — Automatic problem repair

⏱️ Estimated read: 12 min | |

The --fix flag is ESLint’s mechanism for applying safe corrections to code without manual intervention. When a rule provides a fix, it is marked with a wrench icon (🔧) in the rules documentation, and ESLint can apply that fix automatically during a lint run . The flag does not fix everything. It fixes only the problems for which a rule author has written a deterministic correction, and it applies those corrections in a controlled, multi-pass process that prevents infinite loops. The rest of the problems remain as reports, and the exit code reflects them.

The flag was introduced in ESLint v1.4.0 in September 2015, with autofixing implemented for three rules: semi, eqeqeq, and quotes . The feature was described as experimental at the time, and the documentation noted that it would not work for piped-in text and had no effect on code using ESLint processors. Over a decade later, the flag is stable, the rule coverage is extensive, and the --fix-dry-run variant provides the same corrections without writing to disk .

Key point: --fix applies only the fixes that rules declare as safe. It runs in multiple passes, re-linting after each round of fixes until no more can be applied or the pass limit is reached. Problems that cannot be fixed remain reported, and the exit code is non-zero if any remain. The --fix-type flag filters which categories of fixes are applied.


Why --fix is a controlled, multi-pass operation

The safety constraint. A fix is not a guess. The rule author must declare that the correction is safe—that it does not change the program’s behavior. The documentation states this explicitly: fixes “safely correct the violation without changing application logic” . A rule like no-unused-vars does not have a fix, because removing a variable might change behavior if the variable is used indirectly. A rule like semi has a fix, because adding or removing a semicolon is a syntax-level correction that does not alter semantics. The wrench icon is the signal that a fix exists and is safe.

The multi-pass loop. Applying fixes can create new problems or expose problems that were previously masked. ESLint handles this by running multiple passes: it applies the fixes it finds, re-lints the corrected code, applies any new fixes, and repeats until no more fixes are applied or the maximum pass count (10) is reached . This is why a single --fix run can produce a codebase that is fully corrected even when one fix enables another. The limit prevents a pathological rule from looping indefinitely.

The --fix-type filter. Not all fixes are equally desirable in all contexts. A project that uses Prettier for formatting may want ESLint’s problem fixes but not its layout fixes. The --fix-type flag filters the fixes by category: problem (potential errors), suggestion (improvements), layout (whitespace, semicolons, commas, parentheses), and directive (inline directives like // eslint-disable) . The flag is useful when another tool owns formatting and ESLint should only correct logic issues.

The trade-off. --fix is not a substitute for reviewing the corrections. A fix is safe in the sense that it does not change behavior, but it may not match the developer’s intent. A quotes fix changes all quotes to a single style, which is what the rule is for, but a developer who intentionally used a different style in a specific file will find the change unwelcome. The flag is a batch operation, and batch operations require a clean working tree and a review of the diff.


a. The basic usage and the exit code behavior

The flag is passed on the command line alongside the file patterns. When fixes are applied, the problems that were fixed are not reported. The problems that remain are reported, and the exit code is non-zero if any remain.

# Run ESLint with --fix on the src directory.
# Fixable problems are corrected and removed from the report.
# Unfixable problems are reported.
npx eslint src --fix
// package.json — a lint:fix script
{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
}

The script is the standard pattern. The lint script reports problems without modifying files; the lint:fix script modifies files and reports what remains. In a CI pipeline, the lint script is the gate. In a local development workflow, the lint:fix script is the correction step before committing .

# The exit code is 1 if any unfixable problems remain.
# This is what makes the command usable as a CI gate.
npx eslint . --fix
echo $? # 0 if all problems were fixed or none existed, 1 otherwise

The exit code behavior is the reason --fix can be used in CI. A pipeline that runs eslint . --fix and checks the exit code will fail if there are problems that cannot be fixed automatically. The fixed files are modified in the working tree, and the pipeline fails because the remaining problems still exist. A pipeline that wants to apply fixes without failing on unfixable problems would need to check the exit code and handle it explicitly, but the standard pattern is to use lint without --fix as the gate and lint:fix as a local convenience.


b. The --fix-dry-run variant and the --fix-type filter

The --fix-dry-run variant applies the same fixes but does not write them to disk. It is useful for integrations that need to know what the fixes would be without modifying the file system.

# Apply fixes without saving them.
# The corrected code is available in the output only if a formatter
# that includes the fixed text is used (e.g., json).
npx eslint src --fix-dry-run --format=json

The --fix-dry-run flag is documented as having the same effect as --fix except that the fixes are not saved to the file system . It is the flag that editor plugins use when they want to apply fixes in memory and show the corrected text without writing to the file. The default formatter does not output the fixed code, so a formatter that includes the corrected text—such as the JSON formatter—is required to see the result.

# Apply only problem and suggestion fixes, not layout fixes.
# This is the pattern for a project that uses Prettier for formatting.
npx eslint src --fix --fix-type problem,suggestion

The --fix-type filter is the mechanism for separating ESLint’s fixes from Prettier’s formatting. A project that uses both tools can configure ESLint to apply only problem and suggestion fixes, leaving layout fixes to Prettier. The layout category covers whitespace, semicolons, commas, and parentheses—the same concerns that Prettier handles . Filtering those out of ESLint’s fixes prevents the two tools from fighting over the same lines.

# Apply only directive fixes.
# This corrects inline // eslint-disable comments
# without touching the code itself.
npx eslint src --fix --fix-type directive

The directive category is for fixes to inline directives. A rule that manages eslint-disable comments can provide a fix that removes an unnecessary directive or corrects a malformed one. The directive filter isolates those fixes from the code corrections.


Complete Example Session

// ============================================
// PART 1: THE FIXABLE RULE
// ============================================

// A rule with a fix is marked with 🔧 in the rules docs.
// The semi rule is a fixable rule.
// The no-unused-vars rule is not.

// src/app.js — before --fix
const greeting = "hello"   // missing semicolon, double quotes
const unused = "world"     // unused variable

// ============================================
// PART 2: THE LINT REPORT
// ============================================

// npx eslint src/app.js
// error  Missing semicolon        semi
// error  Strings must use singlequote  quotes
// error  'unused' is assigned a value but never used  no-unused-vars

// The semi and quotes problems have fixes.
// The no-unused-vars problem does not.

// ============================================
// PART 3: THE --fix RUN
// ============================================

// npx eslint src/app.js --fix
// The semi and quotes problems are corrected.
// The no-unused-vars problem remains reported.
// The exit code is 1 because a problem remains.

// src/app.js — after --fix
const greeting = 'hello';
const unused = 'world'; // still unused, still reported

// ============================================
// PART 4: THE MULTI-PASS BEHAVIOR
// ============================================

// A fix can expose another fix.
// Example: a rule that adds a semicolon,
// then the quotes rule corrects the quote style.
// ESLint runs multiple passes until no more fixes apply.
// The maximum is 10 passes.

// ============================================
// PART 5: THE EXIT CODE
// ============================================

// --fix does not guarantee a clean exit.
// The exit code is 1 if any unfixable problems remain.
// In CI, use `eslint .` without --fix as the gate.
// The --fix flag is for local correction, not for CI gating.

// ============================================
// PART 6: THE --fix-type FILTER
// ============================================

// npx eslint src --fix --fix-type problem,suggestion
// This applies only problem and suggestion fixes.
// Layout fixes (whitespace, semicolons, commas) are skipped.
// This is the pattern when Prettier owns formatting.

// ============================================
// PART 7: THE --fix-dry-run VARIANT
// ============================================

// npx eslint src --fix-dry-run --format=json
// The fixes are computed but not written.
// The JSON formatter includes the corrected text.
// This is the pattern for editor integrations.

// ============================================
// PART 8: THE CONFLICTING FIXES WARNING
// ============================================

// ESLint v9.23.0 added a warning for conflicting fixes.
// If two rules disagree on how to fix the same code,
// the fixed code satisfies neither rule.
// ESLintCircularFixesWarning is emitted.
// The fix is to resolve the rule conflict in the config.

// Example: @stylistic/semi says no semicolons,
// @stylistic/js/semi says always semicolons.
// No fix can satisfy both.

// ============================================
// PART 9: THE PROCESSOR LIMITATION
// ============================================

// --fix has no effect on code that uses ESLint processors,
// unless the processor opts into allowing autofixes.
// A processor is a plugin that extracts code from non-JS files
// (e.g., Markdown code blocks) for linting.
// The fix cannot be mapped back to the original file
// without the processor's cooperation.

// ============================================
// PART 10: THE VERIFICATION CHECKLIST
// ============================================

// [ ] The working tree is clean before running --fix.
// [ ] The --fix run is followed by a review of the diff.
// [ ] The exit code is checked; unfixable problems remain.
// [ ] The --fix-type filter is used if Prettier owns formatting.
// [ ] The --fix-dry-run variant is used for integrations.
// [ ] The config is checked for conflicting fixes if warnings appear.

The ten parts covered the fixable rule, the report, the fix run, the multi-pass behavior, the exit code, the fix-type filter, the dry-run variant, the conflict warning, the processor limitation, and the verification checklist. The through-line is that --fix is a controlled batch operation, not a guarantee of a clean codebase.


Quick Reference

The flags

FlagEffectWrites to disk?
--fixApplies fixesYes
--fix-dry-runComputes fixes without savingNo
--fix-typeFilters fixes by categoryN/A

The fix types

TypeCoversUse case
problemPotential errorsAlways
suggestionImprovementsAlways
layoutWhitespace, semicolons, commas, parenthesesSkip if Prettier owns formatting
directiveInline eslint-disable commentsOptional

The rule marking

SymbolMeaning
🔧Rule provides a fix
(no symbol)Rule does not provide a fix

Best Practices

✅ Do This:

# Run --fix locally before committing
npx eslint . --fix                                                # ✅

# Use --fix-type to avoid conflicts with Prettier
npx eslint . --fix --fix-type problem,suggestion                  # ✅

# Use --fix-dry-run for integrations
npx eslint . --fix-dry-run --format=json                          # ✅

# Review the diff after --fix
git diff                                                          # ✅

❌ Don’t Do This:

# Use --fix as a CI gate
npx eslint . --fix # exit code 1 if unfixable problems remain      # ❌

# Run --fix on a dirty working tree
npx eslint . --fix # mixes fixes with unrelated changes           # ❌

# Expect --fix to correct every problem
# Only rules with the 🔧 symbol have fixes.                        # ❌

Common Pitfalls

PitfallWhy It HappensFix
Exit code is 1 after --fixUnfixable problems remainReview the remaining reports
Fixes conflict with PrettierLayout fixes applied by ESLintUse --fix-type problem,suggestion
Fixes are not appliedRule has no fix (no 🔧)Check the rule documentation
Conflicting fixes warningTwo rules disagree on the fixResolve the rule conflict in the config
--fix has no effect on MarkdownProcessor does not support fixesThe processor must opt in

Real-World Examples

1. Basic fix

npx eslint src --fix

2. Lint fix script

"lint:fix": "eslint . --fix"

3. Dry run

npx eslint src --fix-dry-run --format=json

4. Filter out layout fixes

npx eslint src --fix --fix-type problem,suggestion

5. Directive fixes only

npx eslint src --fix --fix-type directive

6. Exit code check

npx eslint . --fix; echo $?

7. Pre-commit hook

"*": "eslint --fix"

8. Conflicting fixes warning

ESLintCircularFixesWarning: Circular fixes detected

9. Processor limitation

--fix has no effect on code that uses ESLint processors

10. Review the diff

git diff

Visual

The Multi-Pass Loop

┌──────────────────────────────────────────────────────────────┐
│  HOW --fix APPLIES CORRECTIONS                                │
│                                                              │
│  Pass 1: Lint the source                                     │
│         │                                                    │
│         ▼                                                    │
│  ┌─────────────────────┐                                    │
│  │ Find fixable        │                                    │
│  │ problems            │                                    │
│  └──────────┬──────────┘                                    │
│             │                                                │
│             ▼                                                    │
│  ┌─────────────────────┐                                    │
│  │ Apply fixes         │                                    │
│  └──────────┬──────────┘                                    │
│             │                                                │
│             ▼                                                    │
│  Pass 2: Re-lint the fixed source                            │
│         │                                                    │
│         ▼                                                    │
│  ┌─────────────────────┐                                    │
│  │ New fixes?          │──── Yes ──▶ Apply, repeat          │
│  └──────────┬──────────┘                                    │
│             │ No                                             │
│             ▼                                                    │
│  ┌─────────────────────┐                                    │
│  │ Report remaining    │                                    │
│  │ problems            │                                    │
│  └─────────────────────┘                                    │
│                                                              │
│  Maximum 10 passes. The limit prevents infinite loops.      │
└──────────────────────────────────────────────────────────────┘

The Fixable vs Unfixable Split

┌──────────────────────────────────────────────────────────────┐
│  WHAT --fix CAN AND CANNOT CORRECT                            │
│                                                              │
│  Fixable (🔧)                   Unfixable                     │
│  ┌─────────────────────┐       ┌─────────────────────┐     │
│  │ semi                │       │ no-unused-vars      │     │
│  │ quotes              │       │ no-undef            │     │
│  │ indent              │       │ eqeqeq (no fix)     │     │
│  │ comma-dangle        │       │                     │     │
│  └─────────────────────┘       └─────────────────────┘     │
│                                                              │
│  --fix corrects the left column.                            │
│  The right column remains reported.                         │
│  The exit code is 1 because of the right column.            │
└──────────────────────────────────────────────────────────────┘

The Fix-Type Filter

┌──────────────────────────────────────────────────────────────┐
│  SEPARATING ESLINT FROM PRETTIER                              │
│                                                              │
│  --fix (all types)                                           │
│  ┌─────────────────────┐                                    │
│  │ problem             │                                    │
│  │ suggestion          │                                    │
│  │ layout              │  ← conflicts with Prettier         │
│  │ directive           │                                    │
│  └─────────────────────┘                                    │
│                                                              │
│  --fix --fix-type problem,suggestion                         │
│  ┌─────────────────────┐                                    │
│  │ problem             │                                    │
│  │ suggestion          │                                    │
│  │ (layout skipped)    │  ← Prettier owns this              │
│  └─────────────────────┘                                    │
│                                                              │
│  The filter is the separation mechanism.                    │
└──────────────────────────────────────────────────────────────┘

Summary

ItemValue
Flag--fix
Writes to diskYes
Dry-run variant--fix-dry-run
Type filter--fix-type
Fixable rulesMarked with 🔧
Multi-pass limit10 passes
Exit code1 if unfixable problems remain
Processor supportOnly if the processor opts in

Key takeaways:

  • --fix applies only the fixes that rules declare as safe. A rule with the 🔧 symbol provides a fix; a rule without it does not. The flag does not correct every problem, and the problems that remain are reported with a non-zero exit code .
  • The fixes are applied in multiple passes. Applying one fix can expose another. ESLint re-lints after each round and repeats until no more fixes apply or the pass limit is reached. The limit prevents infinite loops .
  • --fix-type filters the fixes by category. The problem, suggestion, layout, and directive categories can be selected independently. The layout category is the one to skip when Prettier owns formatting .
  • --fix-dry-run computes fixes without writing. It is the variant for editor integrations and for any tool that needs the corrected text without modifying the file system. The JSON formatter is required to see the corrected output .
  • Conflicting fixes produce a warning, not a silent failure. When two rules disagree on how to fix the same code, ESLint v9.23.0 and later emits an ESLintCircularFixesWarning. The fix is to resolve the rule conflict in the configuration, not to run --fix again .

Remember: --fix is a batch correction tool, not a guarantee of a clean codebase. It corrects what the rules declare as safely correctable, reports what remains, and exits with a non-zero code if anything is left. The flag is for local development and for the lint:fix script. The CI gate is the lint script without --fix. The --fix-type filter is the separation mechanism when Prettier owns formatting. The flag does not think; it applies the corrections that the rule authors have written.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!