Side by side
LintingvsCode Formatter
What is the difference between a linter and a formatter?
Updated 3 min read7 differences
In short
A linter analyzes code for likely bugs and risky patterns and reports them; a formatter only rewrites layout, such as indentation and line breaks.
Linting
Linting is the automated analysis of source code, without running it, to flag likely bugs, style problems, and suspicious patterns before the code ships.
Read the page on LintingCode Formatter
A code formatter is a tool that rewrites source code into one consistent layout, fixing indentation, spacing and line breaks without changing what it does.
Read the page on Code FormatterLinting and Code Formatter compared
| Aspect | Linting | Code Formatter |
|---|---|---|
| Looks at | What the code does: likely bugs, risky patterns, conventions | How the code looks: indentation, spacing, line breaks, quotes |
| Output | A list of warnings and errors, some with automatic fixes | The same code, rewritten in a consistent layout |
| Needs judgment | Yes: a person fixes, ignores or disables each warning | No: the tool decides the whole result |
| Configuration | Many rules, each set to off, warn or error | Few options by design; gofmt has none for style |
| Catches bugs | Yes, such as an unused variable or a missing await | No; it never judges the logic |
| Examples | ESLint, Pylint, Ruff, Clippy, golangci-lint | Prettier, Black, gofmt, rustfmt, clang-format |
| In CI | Fails the build when rules report errors | Fails the build when a file isn't formatted, as with prettier --check |
The difference, explained
Both read source code without running it, but they look for different things. A linter, such as ESLint, Pylint, Ruff or Clippy, checks the code against a set of rules and reports likely bugs and questionable patterns: an unused variable, a missing await, an assignment inside a condition. A formatter, such as Prettier, Black, gofmt or rustfmt, rewrites the code's layout into one consistent style, fixing indentation, spacing, line breaks and quotes, without changing what the code does.
The essential difference is meaning versus appearance. A linter judges what the code does, and a person, or an automatic fix, decides how to resolve each warning; its rules are configurable, and many of them are about correctness. A formatter makes no judgments: it parses the code, throws the old layout away and prints it again, so the result is the same whoever wrote it, and there is nothing left to discuss.
Teams usually run both, in the editor on save, in a pre-commit hook and as a check in CI, with the formatter owning every layout decision and the linter's style rules turned off so the two don't fight. ESLint deprecated its own formatting rules in 2023 for that reason, and configs such as eslint-config-prettier switch off any that clash. Some newer tools, such as Ruff and Biome, ship a linter and a formatter together.
A common misconception is that a formatter makes a linter unnecessary, or the reverse. Perfectly formatted code can still have an unused variable or a forgotten await, and a linter that enforces spacing does a formatter's job slowly, one warning at a time. Neither replaces tests, since neither runs the code.
Which one should you use?
Choose Linting when…
- You want to catch likely bugs, such as unused variables or unhandled promises, before review.
- The team needs to enforce conventions, such as banned APIs or naming rules.
- You want warnings in the editor as you type, not only after tests fail.
Choose Code Formatter when…
- Style debates and whitespace comments are slowing down code review.
- Diffs should show only real changes, not reformatting.
- Code from many people and tools should look the same, with almost no configuration.
The same function through a linter and a formatter
// Linter (ESLint): reports problems; the layout is left alone
async function save(user){
const id=user.id
db.write(user)
return true
}
// 1:1 error Async function 'save' has no 'await' expression require-await
// 2:9 error 'id' is assigned a value but never used no-unused-vars// Formatter (Prettier): rewrites the layout; the problems are left alone
async function save(user) {
const id = user.id;
db.write(user);
return true;
}
// Still unused, still not awaited: formatting doesn't judge the logicReaders ask
Do I need both a linter and a formatter?
Usually yes, since they catch different things. Let the formatter own layout, turn off the linter's style rules, and run both on save and in CI. Tools such as Ruff and Biome bundle the two.
Can ESLint format code?
It used to, with rules for spacing, quotes and semicolons, but ESLint deprecated them in 2023 and recommends a dedicated formatter. Those rules live on in the community-maintained ESLint Stylistic project.
Is Prettier a linter?
No. Prettier only reformats code and never reports bugs. Running it with --check in CI makes it fail when a file isn't formatted, which can look like linting, but it still checks only layout.