Fix ESLint and Prettier Conflicts in Claude Code Projects
The Problem
Claude Code writes code that passes Prettier formatting but fails ESLint, or vice versa. You see conflicting errors like:
error Replace `·····` with `····` prettier/prettier
error Expected indentation of 4 spaces but found 2 indent
Or Claude Code fixes one linting error and introduces another because ESLint’s formatting rules conflict with Prettier’s output. This creates an endless loop of fixes.
Quick Fix
Install eslint-config-prettier to disable all ESLint rules that conflict with Prettier:
npm install --save-dev eslint-config-prettier
Add it as the last item in your ESLint extends array:
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
]
}
This disables every ESLint rule that Prettier handles, eliminating all conflicts.
What’s Happening
ESLint and Prettier both have opinions about code formatting. ESLint has rules like indent, semi, quotes, and max-len that control formatting. Prettier also controls these same aspects but with its own logic. When both tools run, they can produce contradictory requirements.
For example, ESLint’s indent rule might require 4 spaces while Prettier is configured for 2 spaces. Claude Code writes code with 2-space indentation (following Prettier), and ESLint immediately flags it as an error.
The solution is to let Prettier handle all formatting and let ESLint handle only code quality rules (unused variables, type errors, potential bugs).
Step-by-Step Fix
Step 1: Audit current configuration
Ask Claude Code to check for conflicts:
Check my ESLint and Prettier configurations for conflicting rules.
List every ESLint rule that overlaps with Prettier's formatting.
Claude Code will read your .eslintrc.*, eslint.config.*, and .prettierrc.* files and identify overlapping rules like:
indent/@typescript-eslint/indentsemi/@typescript-eslint/semiquotes/@typescript-eslint/quotescomma-danglearrow-parensmax-len/printWidthobject-curly-spacingarray-bracket-spacing
Step 2: Install the compatibility package
npm install --save-dev eslint-config-prettier
For ESLint 9+ with flat config:
npm install --save-dev eslint-config-prettier
Step 3: Update ESLint configuration
For flat config (eslint.config.js) - ESLint 9+:
import eslintConfigPrettier from 'eslint-config-prettier';
import tseslint from 'typescript-eslint';
export default [
...tseslint.configs.recommended,
eslintConfigPrettier, // Must be last
{
rules: {
// Your custom code quality rules (not formatting)
'no-console': 'warn',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/explicit-function-return-type': 'warn',
},
},
];
For legacy config (.eslintrc.json):
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"prettier"
],
"rules": {
"no-console": "warn",
"@typescript-eslint/no-unused-vars": "error"
}
}
The "prettier" entry must be last in the extends array because it overrides all previous formatting rules.
Step 4: Configure Prettier
Create or update .prettierrc:
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100,
"arrowParens": "always",
"endOfLine": "lf"
}
Step 5: Remove conflicting ESLint rules
After adding eslint-config-prettier, manually remove any formatting rules you had in your ESLint config:
Review my ESLint config and remove any formatting rules that
Prettier now handles. Keep only code quality rules.
Rules to remove (Claude Code will identify the full list):
// Remove all of these from your ESLint rules:
// indent, semi, quotes, comma-dangle, arrow-parens,
// object-curly-spacing, array-bracket-spacing, max-len,
// no-mixed-spaces-and-tabs, no-trailing-spaces,
// space-before-function-paren, keyword-spacing,
// @typescript-eslint/indent, @typescript-eslint/semi,
// @typescript-eslint/quotes, @typescript-eslint/comma-dangle,
// @typescript-eslint/member-delimiter-style
Step 6: Set up format-on-save in your editor
Configure VS Code to run Prettier on save and ESLint for diagnostics:
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["javascript", "typescript", "typescriptreact"]
}
Step 7: Add a pre-commit hook
Ensure consistency across your team with lint-staged:
npm install --save-dev husky lint-staged
npx husky init
Configure lint-staged in package.json:
{
"lint-staged": {
"*.{ts,tsx,js,jsx}": [
"prettier --write",
"eslint --fix --max-warnings 0"
],
"*.{json,md,css}": [
"prettier --write"
]
}
}
Step 8: Update CLAUDE.md
Tell Claude Code about your formatting setup:
## Code Formatting
- Prettier handles all formatting (run `npx prettier --write` on changed files)
- ESLint handles code quality only (no formatting rules)
- Run `npm run lint` before committing
- Zero warnings policy: fix all ESLint warnings, do not suppress with eslint-disable
Verify the Fix
Run both tools and confirm no conflicts:
# Format with Prettier
npx prettier --write "src/**/*.{ts,tsx}"
# Lint with ESLint (should report zero formatting issues)
npx eslint "src/**/*.{ts,tsx}"
# Check for any remaining conflicts
npx eslint-config-prettier "src/**/*.{ts,tsx}"
The eslint-config-prettier CLI tool checks your config for rules that conflict with Prettier and reports them.
Prevention
Keep formatting and linting concerns separate. Prettier owns formatting (whitespace, semicolons, quotes, line length). ESLint owns code quality (unused variables, unreachable code, type safety). Never add formatting rules to ESLint when Prettier is in the project.