ESLint catches code problems and enforces rules; Prettier automatically formats your code consistently. Together they keep a codebase clean, consistent, and bug-free โ essential for teams and worthwhile even solo. This guide sets them up correctly and resolves the common conflicts between them.
๐ Table of Contents
What Each Tool Does
| Tool | Purpose |
|---|---|
| ESLint | Finds problems: unused variables, bugs, bad patterns, style rules |
| Prettier | Formats code: consistent indentation, quotes, line width, semicolons |
The division: ESLint handles code QUALITY (logic, potential bugs), Prettier handles FORMATTING (how it looks). Using both, with Prettier owning formatting, avoids conflicts.
Installation
# Install both plus the integration packages
npm install --save-dev eslint prettier
npm install --save-dev eslint-config-prettier
# eslint-config-prettier turns off ESLint rules that conflict with Prettier
ESLint Configuration (Flat Config, 2026)
// eslint.config.js (flat config - the modern standard)
import js from '@eslint/js';
import prettier from 'eslint-config-prettier';
export default [
js.configs.recommended,
{
languageOptions: {
ecmaVersion: 2025,
sourceType: 'module',
},
rules: {
'no-unused-vars': 'warn',
'no-console': 'warn',
'prefer-const': 'error',
'eqeqeq': 'error', // require === over ==
},
},
prettier, // MUST be last - disables ESLint rules that conflict with Prettier
];
Prettier Configuration
// .prettierrc.json
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 80,
"tabWidth": 2,
"arrowParens": "always"
}
# .prettierignore - files Prettier should skip
node_modules
dist
build
*.min.js
coverage
The Key: Let Prettier Own Formatting
The classic mistake is having ESLint and Prettier both try to format code โ they conflict, fighting over quotes, semicolons, and spacing. The fix is eslint-config-prettier, which disables all ESLint formatting rules so Prettier handles formatting and ESLint handles code quality. Add it LAST in your ESLint config so it overrides conflicting rules.
package.json Scripts
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"format:check": "prettier --check ."
}
}
# Run them
npm run lint # find problems
npm run lint:fix # auto-fix fixable problems
npm run format # format all files with Prettier
npm run format:check # check formatting without changing (for CI)
Format on Save (VS Code)
// .vscode/settings.json - commit this so the whole team gets it
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }
}
With this, saving a file auto-formats it with Prettier and auto-fixes ESLint issues. Consistent code with zero manual effort.
Enforce on Commit with Husky and lint-staged
npm install --save-dev husky lint-staged
npx husky init
// package.json - run linting/formatting only on staged files
{
"lint-staged": {
"*.{js,ts,jsx,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,md,css}": "prettier --write"
}
}
# .husky/pre-commit
npx lint-staged
Now every commit automatically lints and formats staged files โ no unformatted or lint-failing code enters the repo.
TypeScript Setup
npm install --save-dev typescript-eslint
// eslint.config.js with TypeScript
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import prettier from 'eslint-config-prettier';
export default [
js.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
},
},
prettier, // last
];
Frequently Asked Questions
Q: Do I need both ESLint and Prettier?
A: They serve different purposes โ ESLint for code quality/bugs, Prettier for formatting. Using both gives you clean, consistent, bug-catching code. You can use ESLint alone, but Prettier’s automatic formatting is a huge time-saver and eliminates formatting debates.
Q: Why do ESLint and Prettier conflict?
A: Both can enforce formatting rules (quotes, semicolons, spacing), and they disagree. The fix is eslint-config-prettier, which disables ESLint’s formatting rules so Prettier owns formatting and ESLint owns code quality. Add it last in your ESLint config.
Q: Should I run Prettier through ESLint (eslint-plugin-prettier)?
A: Generally no โ running Prettier as an ESLint rule is slower and adds red squiggles for formatting. The recommended setup is running them separately: Prettier for formatting (format on save), ESLint for quality, with eslint-config-prettier to prevent conflicts.
Q: How do I enforce this across my team?
A: Commit the config files (eslint.config.js, .prettierrc, .vscode/settings.json) and set up Husky + lint-staged so commits auto-format. Add format:check and lint to CI so unformatted or failing code can’t merge. This ensures consistency regardless of individual editor setups.
Q: What’s flat config and should I use it?
A: Flat config (eslint.config.js) is the modern ESLint configuration format that replaced the older .eslintrc. It’s the default and recommended in 2026 โ cleaner, more explicit, and better for composition. Use it for new projects.
Conclusion
ESLint and Prettier together keep your codebase clean and consistent. The setup: install both plus eslint-config-prettier, let Prettier own formatting and ESLint own code quality, add eslint-config-prettier last to prevent conflicts, enable format-on-save in VS Code, and enforce on commit with Husky and lint-staged. The key insight is separating concerns โ Prettier formats, ESLint catches problems โ and using eslint-config-prettier so they don’t fight. Once set up, your code is automatically consistent and lint-clean with zero manual effort, eliminating formatting debates and catching bugs before they ship. It’s a small setup investment that pays off on every file you write.
๐ You might also like
๐ Share this article




โ๏ธ Leave a Comment