Linting is automatic code checking. A linter reads your code and flags problems — bugs, style issues, suspicious patterns — before you even run it.
Think of it like spell check for code. It won’t write your code for you, but it’ll catch the dumb mistakes before they become real problems.
What does a linter catch?
Bugs you’d miss:
// Linter: "you're comparing with = instead of ==="
if (user.role = "admin") { // 🐛 This assigns, doesn't compare
grantAccess();
}
// Linter: "unreachable code after return"
function getPrice() {
return 99;
applyDiscount(); // 🐛 This never runs
}
Consistency issues:
// Some files use single quotes, some use double
const name = "Alice";
const city = 'Brussels';
// Linter enforces one style across the whole project
const name = 'Alice';
const city = 'Brussels';
Potential problems:
// Linter: "variable is defined but never used"
const unusedData = fetchData();
// Linter: "don't use console.log in production"
console.log("debug info");
Popular linters by language
| Language | Linter | Install |
|---|---|---|
| JavaScript/TypeScript | ESLint | npm install -D eslint |
| Python | Ruff (or Flake8, Pylint) | pip install ruff |
| CSS | Stylelint | npm install -D stylelint |
| Go | go vet + golangci-lint | Built-in / brew install golangci-lint |
| Rust | Clippy | rustup component add clippy |
| Shell/Bash | ShellCheck | brew install shellcheck |
Setting up ESLint (JavaScript)
# Install
npm init @eslint/config@latest
# Run
npx eslint src/
# Fix automatically
npx eslint src/ --fix
ESLint creates an eslint.config.js file where you configure rules:
import js from '@eslint/js';
export default [
js.configs.recommended,
{
rules: {
'no-unused-vars': 'warn',
'no-console': 'warn',
},
},
];
See also: ESLint parsing error fix if you run into setup issues.
Setting up Ruff (Python)
# Install
pip install ruff
# Check
ruff check .
# Fix automatically
ruff check --fix .
# Format (like Black)
ruff format .
Ruff is the new standard — it’s 10-100x faster than Flake8 or Pylint because it’s written in Rust.
Linting in your editor
The real power of linting is seeing errors as you type, not after you run a command.
VS Code:
- Install the ESLint extension (JavaScript)
- Install the Ruff extension (Python)
- Errors show as red/yellow squiggly lines in real time
Enable format on save:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
Linting in CI/CD
Add linting to your GitHub Actions so bad code can’t be merged:
- run: npx eslint src/
If the linter finds errors, the build fails and the PR can’t be merged. This keeps your codebase clean without relying on humans to remember.
See also: GitHub Actions cheat sheet
Linting vs. formatting
They’re related but different:
- Linter (ESLint, Ruff): finds bugs and enforces code quality rules
- Formatter (Prettier, Black, Ruff format): fixes code style (indentation, spacing, quotes)
Most teams use both. The formatter handles how code looks, the linter handles how code works.
Should you use a linter?
Yes. Every project, every language, no exceptions. The 5 minutes it takes to set up will save you hours of debugging. It’s one of those things where once you start using it, you can’t imagine coding without it.