ESLint 17 🛡️ –fix-dry-run — Previewing fixes without writing
The --fix-dry-run flag is the preview counterpart to --fix. It runs the same multi-pass correction pipeline, computes the same fixes, and produces the same corrected code—but it does not write the result to disk. The flag was added in ESLint v4.9.0 specifically with editor plugins in mind: in some cases an integration can only communicate over stdin/stdout, and without a dry-run mode, enabling autofix in those tools was “close to impossible” . The corrected text is emitted in the lint result’s output field, but the default formatter does not display it. A different formatter, such as json, is required to see the result .
The distinction between --fix and --fix-dry-run is not the computation. Both apply the same fixes, in the same order, with the same pass limit. The difference is the write. --fix modifies the files on disk; --fix-dry-run leaves them untouched and puts the corrected text in the output. This makes the flag the correct choice for any tool that wants to inspect the fix before committing to it, or for a workflow where the corrected output needs to be piped to another process rather than written in place.
Key point: --fix-dry-run applies the same fixes as --fix but does not write to the file system. The corrected text is available in the output field of the JSON lint result. The default formatter does not show it, so --format=json is required to see the corrected code.
Why the dry-run flag exists
The stdin/stdout integration problem. Editor plugins and integrations do not always have file system access. They receive the source code over stdin, lint it, and return the result over stdout. The --fix flag is incompatible with this model because it writes to disk, and the plugin may not have a file to write to. The --fix-dry-run flag solves this by computing the fixes without writing, and the corrected text is returned in the output. The commit that added the flag describes this exact motivation .
The pre-commit hook problem. A pre-commit hook that runs eslint --fix modifies the files in the working tree, which means the hook is mutating the code that is being committed. A hook that wants to check whether the staged code is fixable without modifying it needs a different mechanism. The --fix-dry-run flag provides the corrected text without the write, so the hook can compare the output to the staged content and decide whether to fail or to apply the fix separately. A custom formatter like eslint-formatter-fix-dry-run exists for this exact use case: it outputs only the fixed file content to stdout, with no JSON wrapper, so a script can use it directly without parsing .
The review-before-apply problem. A developer who is unfamiliar with a rule’s fix may want to see what the fix would do before applying it. The --fix-dry-run flag produces the corrected code, and the developer can review the diff—the original source against the output field—before running --fix. The flag is a preview, not a commitment.
The trade-off. The dry-run flag does not provide a summary of what changed. It provides the corrected text, and the caller must compare it to the original to determine what the fixes did. The default formatter does not display the corrected text at all, so a caller that runs eslint --fix-dry-run without --format=json sees only the remaining problems, not the fixes that were computed. The flag is a primitive for integrations, not a user-facing preview command.
a. Using the flag with the JSON formatter
The corrected text is in the output field of the JSON lint result. The default formatter does not include this field in its output, so the json formatter is required.
# Run --fix-dry-run with the JSON formatter.
# The output is a JSON array of LintResult objects.
# Each result has an "output" field containing the corrected text.
npx eslint src/app.js --fix-dry-run --format=json
// The JSON output (simplified)
[
{
"filePath": "/path/to/src/app.js",
"messages": [],
"errorCount": 0,
"warningCount": 0,
"fixableErrorCount": 0,
"fixableWarningCount": 0,
"output": "const greeting = 'hello';\n"
}
]
The messages array contains the problems that were not fixed. The output field contains the corrected text. If no fixes were applied, the output field may be absent or identical to the input. The fixableErrorCount and fixableWarningCount fields indicate how many problems had fixes available, even if the dry-run was not used to apply them .
# Filter the output to just the corrected text with jq.
# The output field is the only thing needed for a preview.
npx eslint src/app.js --fix-dry-run --format=json | jq -r '.[0].output'
The jq pipeline is the simplest way to extract the corrected text for review. The output field is a string, and -r outputs it raw (without JSON quotes and escaping). A script that compares this output to the original file can determine whether the fixes would change anything.
b. The --fix-type filter with dry-run
The --fix-type flag works with --fix-dry-run exactly as it works with --fix. The filter restricts which categories of fixes are computed.
# Compute only problem and suggestion fixes.
# Layout fixes are skipped, which is the pattern when Prettier owns formatting.
npx eslint src --fix-dry-run --fix-type problem,suggestion --format=json
The documentation for --fix-type states that it applies “when using either --fix or --fix-dry-run” . The four categories are the same: problem, suggestion, layout, and directive. A dry-run with --fix-type layout computes only the layout fixes and ignores the others. This is useful for a preview of what a formatting-only pass would do, or for a workflow that wants to separate the layout corrections from the logic corrections.
# Preview only the layout fixes.
# This is the equivalent of "what would Prettier-style fixes do?"
npx eslint src --fix-dry-run --fix-type layout --format=json
The combination of --fix-dry-run and --fix-type is the most granular preview the CLI offers. It computes a subset of the fixes without writing, and the corrected text reflects only that subset.
Complete Example Session
// ============================================
// PART 1: THE BASIC DRY-RUN
// ============================================
// A file with a fixable problem and an unfixable one.
// src/app.js:
// const greeting = "hello" // missing semicolon, double quotes
// const unused = "world" // unused variable
// npx eslint src/app.js --fix-dry-run --format=json
// The JSON output:
// [
// {
// "filePath": "/path/to/src/app.js",
// "messages": [
// {
// "ruleId": "no-unused-vars",
// "severity": 2,
// "message": "'unused' is assigned a value but never used."
// }
// ],
// "errorCount": 1,
// "fixableErrorCount": 0,
// "output": "const greeting = 'hello';\nconst unused = 'world';\n"
// }
// ]
// The output field contains the corrected text.
// The semi and quotes fixes were applied in the output.
// The no-unused-vars problem remains in messages.
// The file on disk is unchanged.
// ============================================
// PART 2: THE DEFAULT FORMATTER DOES NOT SHOW OUTPUT
// ============================================
// npx eslint src/app.js --fix-dry-run
//
// The output is the same as a normal lint run:
// error 'unused' is assigned a value but never used. no-unused-vars
//
// The corrected text is not shown.
// The default formatter does not include the output field.
// --format=json is required to see it.
// ============================================
// PART 3: EXTRACTING THE CORRECTED TEXT
// ============================================
// npx eslint src/app.js --fix-dry-run --format=json | jq -r '.[0].output'
//
// Output:
// const greeting = 'hello';
// const unused = 'world';
//
// This is the text that --fix would write to disk.
// ============================================
// PART 4: THE FIX-TYPE FILTER
// ============================================
// npx eslint src/app.js --fix-dry-run --fix-type problem --format=json
//
// Only problem fixes are computed.
// Layout fixes (semi, quotes) are skipped.
// The output field still contains the original text,
// or is absent, because no problem fixes were available.
// ============================================
// PART 5: THE CUSTOM FORMATTER
// ============================================
// The eslint-formatter-fix-dry-run package outputs
// only the fixed file content, with no JSON wrapper.
//
// npm install --no-save eslint-formatter-fix-dry-run
// npx eslint src/app.js --fix-dry-run --format=fix-dry-run
//
// Output:
// const greeting = 'hello';
// const unused = 'world';
//
// This is the pattern for a pre-commit hook that wants
// the corrected text without parsing JSON.
// ============================================
// PART 6: THE PRE-COMMIT HOOK PATTERN
// ============================================
// A hook that previews the fixes without writing:
//
// 1. Run eslint --fix-dry-run on the staged files.
// 2. Compare the output field to the file content.
// 3. If they differ, report the fixes that would be applied.
// 4. Do not write the files.
//
// The hook fails if the output differs from the source,
// which tells the developer to run --fix manually.
// ============================================
// PART 7: THE STDIN PATTERN
// ============================================
// The --fix-dry-run flag works with --stdin.
// This is the editor plugin pattern.
//
// echo 'const x=1' | npx eslint --stdin --fix-dry-run --format=json
//
// The output field contains 'const x = 1;\n'.
// The plugin can apply the corrected text to the editor buffer.
// No file is written.
// ============================================
// PART 8: THE EXIT CODE
// ============================================
// The exit code is the same as a normal lint run.
// It is 1 if any problems remain, regardless of the fixes.
// The dry-run does not change the exit code.
// A caller that wants to know "would this pass after fixing?"
// must check the messages array, not the exit code.
// ============================================
// PART 9: THE COMPARISON WITH --FIX
// ============================================
// --fix:
// - Computes the fixes.
// - Writes the corrected text to disk.
// - Reports the remaining problems.
// - Exit code 1 if problems remain.
//
// --fix-dry-run:
// - Computes the fixes.
// - Does not write to disk.
// - Puts the corrected text in the output field.
// - Reports the remaining problems.
// - Exit code 1 if problems remain.
// ============================================
// PART 10: THE VERIFICATION CHECKLIST
// ============================================
// [ ] The --format=json flag is passed to see the output field.
// [ ] The output field is extracted and compared to the source.
// [ ] The file on disk is unchanged after the run.
// [ ] The messages array shows the remaining problems.
// [ ] The --fix-type filter is used if only some fixes are wanted.
// [ ] The --stdin flag is used for editor integrations.
The ten parts covered the basic dry-run, the formatter requirement, the extraction, the fix-type filter, the custom formatter, the pre-commit pattern, the stdin pattern, the exit code, the comparison with --fix, and the verification checklist. The through-line is that --fix-dry-run computes the same corrections as --fix but leaves the write to the caller.
Quick Reference
The flags
| Flag | Writes to disk | Output field |
|---|---|---|
--fix | Yes | No |
--fix-dry-run | No | Yes (in JSON) |
--fix-type | Filter | Filter |
The output field
| Field | Meaning |
|---|---|
output | The corrected text (if fixes were applied) |
messages | The problems that remain after fixes |
fixableErrorCount | Number of problems with fixes available |
The fix types
| Type | Covers |
|---|---|
problem | Potential errors |
suggestion | Improvements |
layout | Whitespace, semicolons, commas, parentheses |
directive | Inline eslint-disable comments |
Best Practices
✅ Do This:
# Use --format=json to see the corrected text
npx eslint src --fix-dry-run --format=json # ✅
# Extract the output field with jq
npx eslint src --fix-dry-run --format=json | jq -r '.[0].output' # ✅
# Use --stdin for editor integrations
echo 'const x=1' | npx eslint --stdin --fix-dry-run --format=json # ✅
# Use --fix-type to preview specific fixes
npx eslint src --fix-dry-run --fix-type problem # ✅
❌ Don’t Do This:
# Expect the default formatter to show the corrected text
npx eslint src --fix-dry-run # no output field shown # ❌
# Expect the file on disk to be modified
npx eslint src --fix-dry-run # the write does not happen # ❌
# Assume the exit code reflects the post-fix state
# The exit code reflects the remaining problems, not the output. # ❌
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Corrected text is not visible | Default formatter does not include output | Use --format=json |
| File is not modified | Dry-run does not write | Use --fix to apply |
output field is missing | No fixes were applied | Check fixableErrorCount |
| Exit code is 1 despite fixes | Unfixable problems remain | Check messages array |
| Custom formatter is not found | Not installed or path is wrong | Install or use --format=json |
Real-World Examples
1. Basic dry-run with JSON
npx eslint src/app.js --fix-dry-run --format=json
2. Extract the corrected text
npx eslint src/app.js --fix-dry-run --format=json | jq -r '.[0].output'
3. Preview only problem fixes
npx eslint src --fix-dry-run --fix-type problem --format=json
4. Stdin dry-run
echo 'const x=1' | npx eslint --stdin --fix-dry-run --format=json
5. Custom formatter
npx eslint src --fix-dry-run --format=fix-dry-run
6. Compare output to source
diff <(cat src/app.js) <(npx eslint src/app.js --fix-dry-run --format=json | jq -r '.[0].output')
7. CI preview
npx eslint src --fix-dry-run --format=json > /tmp/preview.json
8. Check fixable count
npx eslint src --fix-dry-run --format=json | jq '.[0].fixableErrorCount'
9. Layout-only preview
npx eslint src --fix-dry-run --fix-type layout --format=json
10. Remaining problems
npx eslint src --fix-dry-run --format=json | jq '.[0].messages'
Visual
The Difference Between –fix and –fix-dry-run
┌──────────────────────────────────────────────────────────────┐
│ SAME COMPUTATION, DIFFERENT WRITE │
│ │
│ --fix --fix-dry-run │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Lint the source │ │ Lint the source │ │
│ │ Apply fixes │ │ Apply fixes │ │
│ │ Write to disk │ │ Put in output field │ │
│ │ Report remaining │ │ Report remaining │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ The computation is identical. │
│ The write is the difference. │
│ The default formatter does not show the output field. │
└──────────────────────────────────────────────────────────────┘
The JSON Output Structure
┌──────────────────────────────────────────────────────────────┐
│ THE output FIELD │
│ │
│ [ │
│ { │
│ "filePath": "/path/to/app.js", │
│ "messages": [ /* remaining problems */ ], │
│ "errorCount": 1, │
│ "fixableErrorCount": 0, │
│ "output": "const greeting = 'hello';\n" │
│ } │
│ ] │
│ │
│ "messages" = what remains after fixes. │
│ "output" = the corrected text. │
│ The default formatter shows messages but not output. │
└──────────────────────────────────────────────────────────────┘
The Editor Integration Flow
┌──────────────────────────────────────────────────────────────┐
│ STDIN → LINT → OUTPUT → EDITOR BUFFER │
│ │
│ Editor sends source over stdin: │
│ ┌─────────────────────┐ │
│ │ const x=1 │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ eslint --stdin --fix-dry-run --format=json │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ output: "const x = 1;\n"│ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ Editor applies the output to the buffer. │
│ No file is written. The buffer is updated. │
└──────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Flag | --fix-dry-run |
| Added | ESLint v4.9.0 |
| Writes to disk | No |
| Output field | output in JSON result |
| Required formatter | json (or a custom formatter) |
| Works with | --fix-type, --stdin |
| Exit code | Same as --fix (1 if problems remain) |
Key takeaways:
--fix-dry-runcomputes the same fixes as--fixbut does not write. The corrected text is available in theoutputfield of the JSON lint result. The default formatter does not display it, so--format=jsonis required to see the corrected code .- The flag exists for integrations that cannot write to disk. Editor plugins that communicate over stdin/stdout use it to get the corrected text and apply it to the editor buffer. Pre-commit hooks use it to preview the fixes without modifying the staged files .
- The
--fix-typefilter works with the dry-run. The same four categories—problem,suggestion,layout,directive—can be selected to preview a subset of the fixes . - A custom formatter can output only the corrected text. The
eslint-formatter-fix-dry-runpackage exists to output the fixed content to stdout without the JSON wrapper, which simplifies scripting for pre-commit hooks and other integrations . - The exit code is not a preview of the post-fix state. The exit code reflects the problems that remain after the fixes, not whether the fixes would make the file clean. A caller that wants to know “would this pass after fixing?” must check the
messagesarray, not the exit code.
Remember: --fix-dry-run is the preview primitive. It runs the same correction pipeline as --fix, but it stops before the write. The corrected text is in the output field, and the default formatter does not show it. The flag is for tools and scripts, not for interactive use. A developer who wants to see what --fix would do runs the dry-run with --format=json and extracts the output field. A tool that wants to apply fixes without touching the file system does the same and writes the output wherever it needs to go. The computation is the same; the write is the difference.
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!