Lint what changed, not the entire codebase. eslint-plugin-diff keeps feedback focused by filtering ESLint output to changed lines.
- Focused feedback: keep lint output tied to changed code.
- Safer lint upgrades: avoid being blocked by legacy violations in untouched files.
- Better developer flow: reduce noise while enforcing existing lint rules.
npm install --save-dev eslint eslint-plugin-diffimport diff from "eslint-plugin-diff";
export default [
// ...your existing config
...diff.configs["flat/diff"],
];{
"extends": ["plugin:diff/diff"]
}This plugin does not provide lint rules. It provides ESLint processors and preset configs.
Behavior:
- It computes changed files from
git diff --name-only. - It skips unchanged files in processor
preprocess(performance optimization). - It filters lint messages in
postprocessto changed line ranges from diff hunks. - Untracked files are treated as changed, so their messages are not filtered out.
| Mode | Legacy config | Flat config | Typical use |
|---|---|---|---|
diff |
plugin:diff/diff |
configs["flat/diff"] |
Local dev against working tree changes |
ci |
plugin:diff/ci |
configs["flat/ci"] |
PR CI diff-only in CI, full lint locally |
staged |
plugin:diff/staged |
configs["flat/staged"] |
Pre-commit staged-only workflows |
Important staged caveat: if a file has unstaged changes, the plugin emits a fatal message:
<file> has unstaged changes. Please stage or remove the changes.
Sets diff base commit-ish. Default: HEAD.
ESLINT_PLUGIN_DIFF_COMMIT="origin/main" npx eslint --max-warnings=0 .ci mode behavior:
CIset: active diff filtering.CInot set: no-op processor (lint everything).
If CI is set and ESLINT_PLUGIN_DIFF_COMMIT is not set, the plugin attempts provider-based target branch detection and fetches from origin before diffing.
When set, the plugin can refresh the initial diff snapshot once to avoid delayed diagnostics in editor workflows.
When set to true, the plugin keeps lint messages with available fixes even
when those messages are outside changed diff hunks. This can make eslint --fix
apply file-wide changes in modified files.
ESLINT_PLUGIN_DIFF_INCLUDE_FIXES=true npx eslint --fix .npx eslint --max-warnings=0 .ESLINT_PLUGIN_DIFF_COMMIT="origin/main" npx eslint --max-warnings=0 .Use plugin:diff/staged or configs["flat/staged"].
Use plugin:diff/ci or configs["flat/ci"] and run ESLint normally in CI.
git fetch --quiet origin main
ESLINT_PLUGIN_DIFF_COMMIT="main" npx eslint --max-warnings=0 .When a file type needs another processor, compose it with diff instead of
overriding one processor with another.
import diffPlugin from "eslint-plugin-diff";
import vuePlugin from "eslint-plugin-vue";
const vueProcessor = vuePlugin.processors.vue ?? vuePlugin.processors[".vue"];
export default [
...vuePlugin.configs["flat/recommended"],
...diffPlugin.configs["flat/diff"].map((config) => ({
...config,
ignores: ["**/*.vue"],
})),
{
files: ["**/*.vue"],
processor: diffPlugin.composeProcessor(vueProcessor, "diff"),
},
];- ESLint allows one processor per file. If another integration requires a processor for the same files, compose processors (see recipe above) or scope one of them by file patterns.
- Diff-only linting is a signal-over-completeness strategy. It can miss issues outside changed lines. Many teams run full lint in scheduled jobs or on protected branches.
Set ESLINT_PLUGIN_DIFF_COMMIT explicitly.
This comes from staged mode with partially staged files.
VSCODE_PID enables a one-time diff refresh path intended to reduce this.
No. Your normal rules stay the same. This plugin changes which files/lines can surface diagnostics.
No. Outside CI it is intentionally a no-op so local linting stays complete.
MIT. See LICENSE.md.