Linting with ESLint
Use ESLint as an automatic code proofreader: understand rules, configs, editor squiggles, fix-on-save, and which warnings to treat as errors.
- 01Explain lint outputRead a rule id, line number, severity, and autofix hint without panic.
- 02Choose rules through configRecognize the shape of an ESLint flat config and common severities.
- 03Wire linting into your editorKnow how VS Code squiggles, quick fixes, and fix-on-save fit together.
What a linter does
A linter is an automatic checker that reads your code and reports likely mistakes before you run the code. ESLint is the most common linter for JavaScript. It can catch a misspelled variable name, a comparison your team has decided to avoid, unreachable code after a return, or a value that was created and then forgotten.
The important word is reads. ESLint usually does not click your page, call your functions, or prove every possible behavior. It parses the file, applies configured rules, and gives you a message with a rule id, a line and column, and a severity: warning or error.
Before you send a message, spell-check can underline a typo. It does not know what you meant to say, but it catches problems early. ESLint gives your JavaScript the same kind of early warning.
- In real life: Red squiggle under a typo
- In JavaScript: A lint message under
totla - In real life: Grammar rule: use a period
- In JavaScript: ESLint rule: use
=== - In real life: Autocorrect fixes a safe typo
- In JavaScript:
--fixchanges safe syntax, such aslettoconst - In real life: Some sentences need a human
- In JavaScript: Some bugs need tests and debugging
Where the analogy stops: A spell-checker understands prose only shallowly, and a linter understands code only through its rules. Passing lint is not the same as proving the program is correct.
Earlier lessons gave you tools, strict mode, semicolons, and coding style. Linting combines those habits into feedback you see while you type. npm and package.json get their own lesson later, so for now just recognize commands like npm init @eslint/config@latest and npx eslint as ways to set up and run the checker.
Choose the clean or misspelled version. These results are recorded from ESLint and checked by this lesson's tests.
script
console.log(totla);Lint this code: rules report messages
INTERACTIVEESLint output is meant to be read like a checklist, not like a scary stack trace. Each message names the rule that spoke. Toggle rules in the playground and notice that rules are independent: the output is the union of the enabled rule results for the selected snippet.
if (score == "10") { console.log("match");}2 recorded ESLint messages. Each message below shows the rule id, severity, line, column, and whether ESLint has a safe autofix.
A useful lint message usually answers four questions: what rule fired, where is the code, how serious is it, and can ESLint safely fix it? Rule ids are searchable, so no-undef means “a name was used but never declared,” and prefer-const means “this let never changes.”
This site does not bundle ESLint into the browser because that would make the lesson heavy. The examples store ESLint’s recorded output, and the lesson tests compare every line number, rule id, message, severity, and autofix flag with a real ESLint 9 Linter run.
ESLint rules and configs
RULEBOOKA rule is one house rule for code. A config is the rulebook ESLint reads before checking files. ESLint 9 uses a flat config file named eslint.config.js by default. A common starting point imports recommended JavaScript rules, then adds project-specific choices.
Teams choose habits so everyone can work in the same house without arguing over every little thing. ESLint puts those habits in one repeatable place.
- In real life: Take shoes off at the door
- In JavaScript:
eqeqeq: use===instead of== - In real life: Quiet hours after 10
- In JavaScript:
no-console: maybe warn in app code - In real life: The posted list on the fridge
- In JavaScript:
eslint.config.js
Where the analogy stops: A house rule is enforced by people. ESLint enforces only the rules enabled in its config, and only on files it checks.
import js from "@eslint/js"; export default [ js.configs.recommended, { languageOptions: { globals: { document: "readonly", console: "readonly" } }, rules: { eqeqeq: "error", "no-unused-vars": "warn" } }];Severities can be written as strings or numbers: off is 0, warn is 1, and error is 2. Warnings are yellow sticky notes: useful, but not always build-breaking. Errors are stop signs. Use errors for bugs or project rules that should fail CI.
| Idea | What it means | Beginner-friendly example |
|---|---|---|
| Rule | One named check | no-undef reports names that were never declared |
| Severity | How loud the rule is | warn for a nudge, error for a stop sign |
| Recommended config | A preset set of rules | js.configs.recommended from @eslint/js |
| Globals | Names ESLint should treat as already available | Browser projects often mark document and console readonly; many teams use the globals package |
| Disable comment | A local escape hatch | // eslint-disable-next-line no-alert with a clear reason |
Sometimes a line is intentionally unusual. Prefer a small disable comment near that line, with a short explanation, over turning a rule off for the whole project. The comment is a note to the next person, not a way to hide confusing code.
Fixing on save
STEP THROUGHSome lint messages are safe to fix mechanically. ESLint calls those fixable. For example, if a variable is declared with let and never reassigned, prefer-const can rewrite it to const without changing the program’s output. Other rules, such as no-undef, usually need a human: ESLint cannot know whether you meant total, totla, or a new variable.
Step through one real autofix. The lesson stores the output from verifyAndFix, and the tests compare it with ESLint.
script
console.log(limit);In a terminal, npx eslint . reports problems and npx eslint . --fix asks ESLint to apply safe fixes. The npm lesson later will explain exactly what npx and project scripts do. For now, read the command as “run ESLint on this project.”
npm init @eslint/config@latestnpx eslint .npx eslint . --fixEditor integration
INTERACTIVEESLint is most helpful when your editor shows it before you switch to the terminal. In VS Code, install the ESLint extension. It reads the project’s config, underlines problems, offers quick fixes, and can apply safe fixes when you save. Recent VS Code settings use "explicit" for save actions; older examples accepted true.
{ "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }}let limit = 3;console.log(limit);Saving can change let limit to const limit because ESLint proved the variable is never reassigned.
When the VS Code ESLint extension sees this setting, saving the file can apply safe ESLint fixes. Recent VS Code uses explicit; older examples sometimes show true.
{ "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }}Editor integration does not replace learning the rule. When a squiggle appears, read the message, look at the line, and decide: accept the quick fix, change the code yourself, or make a deliberate exception. That habit turns linting into coaching instead of noise.
Linter or formatter?
SORTThe previous lesson introduced Prettier formatting. A formatter is a copy editor for layout. It chooses indentation, line wrapping, and other style details so humans stop arguing over them. A linter is more like a proofreader looking for suspicious meaning: unused names, unknown variables, unreachable code, and rules your team chose.
| Tool | Mostly checks | Typical result |
|---|---|---|
| Formatter | How code is laid out | Rewrites spaces, line breaks, quotes, and trailing commas |
| Linter | Whether code violates a rule | Reports a message; sometimes offers a safe fix |
| Both together | Team consistency | Prettier handles layout, ESLint handles code-quality rules |
- A variable is created but never used
- Indentation is inconsistent
- Code uses
==where the team wants=== - A line is too long to read comfortably
- A variable is read before it is declared
- A missing trailing comma in a multiline list
- An extra semicolon after a statement
Sort each issue by the tool that usually helps first. Some teams configure overlap, but these are good beginner defaults.
Where you’ll use linting
In a real project, linting appears in three places. First, the editor shows squiggles while you type. Second, a terminal command checks the whole project before you share work. Third, a team may run the same command in CI, which is an automated check before code is merged.
Imagine building a small shopping-cart page. A linter cannot tell you whether the checkout design is good. It can catch that cartTotal was misspelled as cartTtoal, that code after return will never run, or that two object keys use the same name and one silently overwrites the other.
- Write a small piece of code.
- Read any ESLint squiggle before running the page.
- Apply safe quick fixes, but understand them.
- Run
npx eslint .before you consider the work done. - If a rule feels wrong, ask whether the config or your code should change.
const limit = 3;console.log(limit);Common misconceptions
“If lint passes, the app works.”
Passing lint only means enabled static rules found no problem. You still need to run the code, test behavior, and think.
“Every lint message is a bug.”
Some are style or maintainability warnings. Read the severity and rule id before deciding how urgent it is.
“Autofix means ESLint understands my goal.”
Autofix means the rule author marked a rewrite as safe. It does not mean ESLint knows your product requirement.
“Formatters and linters do the same job.”
They overlap at the edges, but Prettier is mainly layout and ESLint is mainly rule-based code quality.
“Disable comments are harmless.”
They can be correct, but they also hide feedback. Keep them narrow and explain why the exception exists.
Practice: make ESLint useful
5 EXERCISESWhich rule reports the misspelled name in this snippet?
let count = 1;
console.log(cout);The code declares count but logs cout. Because cout is not defined anywhere, ESLint reports no-undef.
Rewrite the snippet so it lints clean with prefer-const, then type what the fixed program prints.
let total = 1 + 2;
console.log(total);const total = 1 + 2;
console.log(total);Changing let to const satisfies prefer-const. The calculation still gives 3, so console.log(total) still prints 3.
In an ESLint config, make strict equality an error.
import js from "@eslint/js";
export default [
js.configs.recommended,
{
rules: {
eqeqeq: "error"
}
}
];rules: {
eqeqeq: "error"
}A rule setting is a property in the rules object. Setting eqeqeq to error makes loose equality a build-stopping lint problem.
Add the VS Code setting from the lesson. What value goes on source.fixAll.eslint?
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}With the VS Code ESLint extension, source.fixAll.eslint set to explicit requests safe ESLint fixes when you save explicitly.
Your team decides that unknown variables should never be merged. Should no-undef be a warning or an error?
Choose error for a rule that should fail CI or block merging. Choose warn for guidance that should be visible but not stop the work yet.
Quiz: check your understanding
7 QUESTIONSTry each question before opening explanations. Several choices are plausible, because real linting decisions are about tradeoffs.
Question 1 of 7What is a linter's main job?
Choose an answer to see the explanation.
Question 2 of 7Which rule reports this code?
Read the code, then predictconsole.log(totla);Choose an answer to see the explanation.
Question 3 of 7In ESLint severities, which setting usually fails a script or CI job?
Choose an answer to see the explanation.
Question 4 of 7What does this program print after ESLint autofixes
prefer-const?Read the code, then predictlet limit = 3; console.log(limit);Choose an answer to see the explanation.
Question 5 of 7Which file name matches ESLint 9's flat config style shown in this lesson?
Choose an answer to see the explanation.
Question 6 of 7Which tool is most likely to fix inconsistent indentation automatically?
Choose an answer to see the explanation.
Question 7 of 7Why should inline disable comments be rare?
Choose an answer to see the explanation.
Key takeaways
- A linter reads code before it runs and reports rule violations.
- ESLint messages include a rule id, severity, line, column, message, and sometimes a safe fix.
- Configs are rulebooks. In ESLint 9,
eslint.config.jsis the default flat config file. - Use
errorfor stop signs andwarnfor guidance. - Fix on save and editor squiggles make linting part of the writing loop.
- Formatters handle layout; linters handle rule-based code quality.
Remember the one-liner.
A linter is an automatic code proofreader: it catches likely mistakes and team-rule violations before you run the code.
Up next: Thinking like a developer.