Linting, Formatting and CI Gates
IntermediateESLint catches bugs, Prettier ends formatting arguments, and CI is what makes either of them matter. A rule nobody enforces is a suggestion.
Overview
The division of labour is worth being clear about: Prettier decides how code looks and has no opinions about correctness, ESLint decides what is allowed and has no business reformatting. Configured together they remove an entire category of review comment, leaving reviewers free to discuss design instead. The part teams get wrong is enforcement — running these locally is optional, and optional checks decay. A CI job that fails the build is what turns a convention into a guarantee.
The Division of Labour
Prettier for formatting, ESLint for correctness, and the type-aware rules that catch real bugs.
// Prettier — formatting only, no correctness opinions
{ "semi": false, "singleQuote": true, "printWidth": 100 }
// ESLint — correctness and consistency (flat config)
export default [
js.configs.recommended,
...tseslint.configs.recommendedTypeChecked, // needs a tsconfig
{
rules: {
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
'react-hooks/exhaustive-deps': 'warn',
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
},
]
// no-floating-promises is the highest-value rule here:
saveProgress() // forgot await — the error vanishes silently
// It catches more production bugs than every formatting rule combined.
// exhaustive-deps is the second: a stale closure in a useEffect
// is one of the hardest React bugs to find by reading.Three Layers of Enforcement
Format on save, block on commit, fail in CI — increasing severity, decreasing frequency.
// 1. Editor — format on save, lint inline
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }
}
// 2. Pre-commit — only the staged files, so it stays fast
// package.json
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"]
}
// husky runs it on commit
// 3. CI — the only layer that cannot be skipped
- run: npm ci
- run: npm run typecheck # tsc --noEmit
- run: npm run lint # eslint --max-warnings=0
- run: npm run test
- run: npm run build
// --max-warnings=0 matters. Warnings that never fail anything
// accumulate until nobody reads the output at all.Introducing Rules to an Existing Codebase
Turning on a rule that produces 900 errors is how linting gets abandoned. Ratchet instead.
// Do not do this on day one:
'@typescript-eslint/no-explicit-any': 'error' // 900 errors, PR abandoned
// Ratchet strategy
// 1. Enable as 'warn' and record the current count
// 2. Fail CI only if the count INCREASES
// 3. Fix a batch in each PR that touches the area
// 4. Flip to 'error' once the count reaches zero
// Formatting the whole repo at once creates one enormous diff.
// Do it in a single commit, then hide it from blame:
git blame --ignore-revs-file .git-blame-ignore-revs
// (add the hash to .git-blame-ignore-revs; GitHub honours it too)
// eslint-disable is fine when justified, and only then:
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- third-party type is wrong
// A bare disable with no reason is a rule that should not exist.Key Points to Remember
- 1Prettier owns formatting and ESLint owns correctness — configure them so they never fight
- 2no-floating-promises and react-hooks/exhaustive-deps catch real bugs, not style preferences
- 3Enforce in three layers: format on save, lint-staged on commit, and a CI job that fails the build
- 4Run eslint with --max-warnings=0, or warnings accumulate until the output is ignored
- 5Introduce new rules as warnings with a ratchet rather than flipping on 900 errors at once
Interview Questions
Sign in to ask AriaWhat is the difference in responsibility between ESLint and Prettier?
Which ESLint rules catch actual bugs rather than style issues?
How would you introduce a strict lint rule into a large existing codebase?
Ask Aria about Linting, Formatting and CI Gates
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.