ESLint in a Real Project
Set up ESLint with the flat config, pick rules that catch bugs instead of arguing about style, and fix or silence findings properly. After this, the linter finds the bug in review instead of production.
Course content
Sign in to save your progress.
-
Functions That Remember
-
JavaScript Closures in Real Code
-
this, bind and Arrow Functions: Who Is Calling
-
-
-
How JavaScript Actually Runs
-
The Event Loop: Microtasks, Macrotasks and Why setTimeout(0) Isn't Zero
-
Running Promises in Parallel: all, allSettled, race
-
Cancelling Work With AbortController
-
-
-
Data That Doesn't Fit in Memory
-
Iterators and Generators
-
Streams in Node.js: Reading Big Files a Piece at a Time
-
-
-
Catch Bugs Before You Run the Code
-
JSDoc Types and // @ts-check Without Switching to TypeScript
-
ESLint in a Real Project
-
-
-
Ship It, Then Make It Fast
-
Bundling With Vite and Publishing to npm
-
Finding Slow Code With the Performance Profiler
-
Memory Leaks: Event Listeners and Closures That Never Let Go
-
-
- Final Check: JavaScript Advanced
Skip ahead: If ESLint already runs in your project and you want to know how to adopt it on old code, skip to "An old project with hundreds of errors".
A linter reads your code without running it and points out patterns that are almost always bugs: a variable that's never defined, an = where you meant ===, an await that does nothing. ESLint is the standard one for JavaScript. Set up well, it catches mistakes in seconds. Set up badly, it argues about semicolons and the team turns it off.
Setup
ESLint 9 and later uses one eslint.config.js file (the "flat config"). ESLint 10 no longer reads old .eslintrc files at all.
npm install --save-dev eslint @eslint/js globals
import js from "@eslint/js";
import globals from "globals";
export default [
js.configs.recommended,
{
files: ["**/*.js"],
languageOptions: {
globals: { ...globals.node },
},
},
];
js.configs.recommended is the set of rules that find real problems. globals.node tells ESLint that process and console exist. For browser code, use globals.browser.
What it finds
Here's a function with two bugs that look fine at a glance:
import { readFile } from "node:fs/promises";
export async function loadReport(path) {
const text = await readFile(path, "utf8");
const rows = text.split("\n");
let total = 0;
for (const row of rows) {
const [status, amount] = row.split(",");
if (status = "paid") total += Number(amount);
}
return totl;
}
npx eslint . (ESLint 10.12; the first line of its output, the file's full path, is left out here):
9:9 error 'status' is constant no-const-assign
9:9 error Expected a conditional expression and instead saw an assignment no-cond-assign
9:9 error Unexpected constant condition no-constant-condition
9:9 error 'status' is assigned a value but never used no-unused-vars
9:26 error 'total' is assigned a value but never used no-unused-vars
11:10 error 'totl' is not defined no-undef
✖ 6 problems (6 errors, 0 warnings)
Six messages, two bugs: = instead of === on line 9, and a typo on line 11. The other messages follow from those. Line 9 would crash at runtime because status is a const. Line 11 would crash too. Neither crash happens until that code runs, which in a rarely used report could be weeks.
Rules: bugs first, style later
recommended is mostly bugs. Add a few more that pay for themselves:
rules: {
eqeqeq: "error",
"no-var": "error",
"prefer-const": "error",
}
Leave formatting (quotes, semicolons, indentation) to Prettier or your editor's formatter. Linters that fight about style get ignored, and then they stop catching bugs too.
Some rules can fix their own findings. npx eslint --fix . changes var to let and let to const where it's safe. Run it, then read the diff before committing.
An old project with hundreds of errors
Turning on ESLint for the first time in a 3-year-old project can give you 500 errors. Nobody fixes 500 errors in one go, and a CI check that fails on day one gets disabled on day two. Do it in this order:
- Run
npx eslint --fix .and commit that alone. It's mechanical and easy to review. - Look at what's left by rule. A handful of rules usually make up most of the count.
- Record the existing problems as a baseline:
npx eslint --suppress-all .writeseslint-suppressions.json. From then on,npx eslint .passes with the old problems and fails on new ones. - Fix the suppressed problems a file at a time, when you're working in that file anyway.
npx eslint --prune-suppressions .removes entries that are already fixed.
$ npx eslint --suppress-all .
$ npx eslint .
$ echo "export const z = (a) => b;" > src/new.js
$ npx eslint .
1:19 error 'a' is defined but never used no-unused-vars
1:25 error 'b' is not defined no-undef
✖ 2 problems (2 errors, 0 warnings)
The old file with six problems passes. The new file fails. That's the behaviour you want: the codebase can only get better.
💡 Tip: Commit eslint-suppressions.json. It's the team's list of known problems, and it shrinks as people fix them.
Silencing one line
When a rule is wrong for one line, disable it on that line, with the reason after --:
// eslint-disable-next-line no-await-in-loop -- pages must be fetched in order
const page = await fetchPage(next);
Never put /* eslint-disable */ at the top of a file to make the errors go away. It also hides the next real bug in that file.
Run it everywhere
- In the editor, so findings show while you type (the ESLint extension in VS Code).
- In
package.json:"lint": "eslint .". - In CI, before tests. A pull request with lint errors doesn't merge.
⚠ Warning: ESLint isn't a type checker. It doesn't know that cartTotal("10%") passes the wrong type. Run it together with tsc --noEmit from the previous lesson. They catch different things.
Common mistakes
- Starting with a strict style guide and getting 2,000 messages about spacing.
- Disabling whole files or whole rules to get CI green.
- Running it only in CI, so people find out after they push.
- Mixing
--fixchanges with real changes in one commit.
What happens if you skip this
= instead of === and a misspelled variable go through review, because humans read what they expect to see. The linter doesn't.
Which of the six messages in the report example would you have noticed in a code review without the linter?
About
Set up ESLint with the flat config, pick rules that catch bugs instead of arguing about style, and fix or silence findings properly. After this, the linter finds the bug in review instead of production.
- Duration
- 5 min
- Last update
- 08/17/2026
Comments (0)
Sign in to commentNo comments yet.