Linter

Tool

A tool that reads code without running it and flags the spots that are valid syntax but likely to turn into a defect, usually the moment you save the file.

Why it exists

Code with broken syntax never runs, so it announces itself immediately. The hard case is code that is perfectly valid and still does something nobody meant. A single character that assigns a value where a comparison belonged. A variable declared and never used. A call that can fail with nothing written down about what happens if it does. Machines run all of this without complaint.

For a long time this work belonged to human eyes, caught during code review — the step where a colleague reads a change before it gets merged. That arrangement cost two things. One was timing: if Theo writes code on Tuesday and someone comments on Thursday, Theo has to reload two-day-old context to fix a one-line mistake. The other was content. When half of a review is "you're not using this variable," there isn't much room left for the conversation about design that the review was actually for.

Consistency was the third problem. One reviewer flags a pattern, another lets it through, and the codebase ends up holding both answers. A linter moves that judgment off people and onto a machine: the rules live in a file, and everyone gets checked against the same file.

What it solves

What a linter catches falls into four groups.

  1. Things nobody uses. Variables declared and never read, functions nobody calls, imports left behind after a rewrite. None of it breaks anything, but it misleads the next reader and often marks code that was supposed to be deleted. Someone six months later spends twenty minutes tracing a function that turns out to have no callers at all.
  2. Syntax that invites mistakes. Writing an assignment where a comparison belongs is the classic. In some languages that line runs cleanly and evaluates as true every time, which quietly disables the whole condition.
  3. Risky habits. Ignoring the result of a call that can fail, or catching an error and then doing nothing with it. These fail silently, which makes them the hardest kind to trace back months later. The system keeps running, the numbers are slightly wrong, and nothing in the logs points at the line responsible.
  4. Rules the team invented. Only this date helper may be used; files in this folder may not import from that one. These aren't language problems — they're local agreements, so somebody writes them in as custom rules.

In practice the tool gets wired into three places. In the editor it underlines the offending line while you type. On the pull request it posts results before a reviewer starts reading. In continuous integration (CI) — the practice of merging often and running automated checks on every change — it blocks the merge outright.

Rules are normally split between errors and warnings. Errors fail the check; warnings only report. Turning on a new rule usually means running it as a warning first, cleaning up what it finds, then promoting it to an error. Flipping straight to error lights up hundreds of unrelated files and buries the change you were actually working on.

Alternatives

Several other things address the same territory, each covering a different slice of it.

  1. The language's type system. Something like TypeScript, where you declare what kind of value goes where, rules out a whole class of defects before any tool runs. A linter reads conventions; this reads the flow of values. It still won't notice an unused variable or a swallowed error.
  2. Static analysis. It follows values across functions and files and finds broader problems. Wider reach, but slower runs and more findings that turn out not to be real. Teams run it nightly or before a merge rather than on every save, so it never gives the instant feedback that makes a linter worth having in the editor.
  3. A written convention doc. Useful to hand a new joiner, and it can say things no rule can encode. What it can't do is tell you whether anyone followed it.
  4. Human review. Questions of judgment stay human. Whether this function belongs in this file, whether the name describes what the code does — no rule expresses that.

None of the four replaces the others; they stack. Clear out what a machine can state as a rule, and what's left for review is the part only a person can decide.

How it sounds at work

"Lint blocked it. I left an unused variable in there."

The check failed on a rule violation and the cause is already known.

"This rule doesn't really fit how we work — can we turn it off?"

Changing one rule changes the standard for everyone, so it isn't a solo decision.

"The linter will catch that, so let's keep review on the structure."

Don't spend review time on what a machine can already see.

At Pagedeck the tool comes up mostly when a rule is being added or removed. When Theo hits the same mistake for the third time and finds a rule that prevents it, the team's first move is to count how many existing files the rule would flag. Ten, and they fix those on the spot and turn it on as an error. Three hundred, and it goes on as a warning, cleaned up gradually whenever someone touches a file that has code smells anyway.

Removal proposals happen too. A rule that gets an inline suppression comment every time it fires isn't preventing anything — it's just producing noise, and the suppressions themselves start looking normal enough that a real one slips through.

What people get wrong

The most common mistake is reading a clean lint run as a verdict on quality. A green check looks like a grade, so the reading is natural. But the tool only sees what's on its rule list. Code that displays the wrong amount, or shows one customer another customer's data, passes quietly as long as the rules are satisfied. Once a team treats passing as quality, effort drifts away from tests and review, and the failures a machine can't see are exactly the ones that grow.

The second mistake is assuming more rules are better. More warnings feel like more coverage. It runs the other way. Past a thousand warnings nobody opens the list, and the genuine problems sitting inside it disappear along with everything else. A rule starts working not when it's switched on but when its violation count reaches zero and it gets promoted to an error.

Easily confused with

TermWhat it looks atHow it differs
FormatterLine breaks, indentation, quotes — the surface shapeIt touches appearance and never meaning, which is why it rewrites the file instead of asking. A linter raises questions about meaning, so most findings need a human decision
Static analysisValue flow across functions and filesBroader reach, longer runs. A linter mostly reasons inside a single file, which is what lets it answer at save time

Where to go next

  • Code quality

    see the activities and principles this tool sits between

  • Formatter

    the tool almost always installed alongside it, so learn how the two split the work

Last updated 2026-09-16