ESLint + Prettier Configuration Reference
ESLint + Prettier configuration reference
TL;DR
- Bottom line: Use ESLint 9 flat config (
eslint.config.mjs) withtypescript-eslintv8 for linting and Prettier as a separate formatter; connect them viaeslint-config-prettieras the last config entry. - Key tool/command:
npx eslint . && npx prettier --check . - Watch out for: Putting
eslint-config-prettieranywhere except last in the config array. - Works with: ESLint 9.x, typescript-eslint 8.x, Prettier 3.x, Node.js 18+.
Constraints
- ESLint 9+ requires flat config (
eslint.config.js/.mjs/.cjs) —.eslintrc.*files are deprecated and ignored by default eslint-config-prettierMUST be the last item in the config array to correctly disable conflicting formatting rules- Never use
eslint-plugin-prettierand manual formatting rules simultaneously — they will conflict typescript-eslintv8+ is required for ESLint 9 flat config compatibility — v7 does not work- Prettier must run as a separate step (or via
eslint-plugin-prettier) — ESLint alone does not format code
Quick Reference
| Setting | Value | Purpose |
|---|---|---|
| Config file | eslint.config.mjs | Flat config (ESM recommended) |
| TypeScript plugin | typescript-eslint@^8 | Type-aware linting for TS files |
| Prettier bridge | eslint-config-prettier | Disables conflicting ESLint formatting rules |
| Alternative bridge | eslint-plugin-prettier | Runs Prettier as an ESLint rule (slower) |
| Prettier config | .prettierrc | Formatting options |
| Globals package | globals | Provides browser, node globals for flat config |
| Lint command | npx eslint . | Run linting |
| Format command | npx prettier --write . | Format all files |
| Check command | npx prettier --check . | Verify formatting without changes |
| Config validator | npx eslint --print-config file.ts | Debug resolved config for a file |
Decision Tree
START
├── Using TypeScript?
│ ├── YES → Install typescript-eslint v8 + @eslint/js
│ └── NO → Install @eslint/js only
├── Want Prettier to run inside ESLint?
│ ├── YES → Use eslint-plugin-prettier/recommended (slower, single command)
│ └── NO → Use eslint-config-prettier (faster, two commands)
├── Using React?
│ ├── YES → Add eslint-plugin-react + eslint-plugin-react-hooks
│ └── NO ↓
├── Need type-aware rules?
│ ├── YES → Use tseslint.configs.recommendedTypeChecked + parserOptions.project
│ └── NO → Use tseslint.configs.recommended (faster)
└── DEFAULT → @eslint/js recommended + eslint-config-prettier
Step-by-Step Guide
1. Install dependencies
Install ESLint 9, typescript-eslint 8, Prettier 3, and the config bridge. [src1]
npm install --save-dev eslint @eslint/js typescript-eslint eslint-config-prettier prettier
Verify: npx eslint --version → expected: v9.x.x
2. Create eslint.config.mjs
Create the flat config file in your project root. [src2]
// eslint.config.mjs
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import eslintConfigPrettier from "eslint-config-prettier";
export default tseslint.config(
{ ignores: ["dist/", "node_modules/", "coverage/"] },
eslint.configs.recommended,
...tseslint.configs.recommended,
{
files: ["**/*.ts", "**/*.tsx"],
rules: {
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
"@typescript-eslint/consistent-type-imports": "error",
},
},
eslintConfigPrettier, // MUST be last
);
Verify: npx eslint --print-config src/index.ts | grep semi → no semi rule (disabled by Prettier)
3. Create Prettier configuration
Define formatting preferences in .prettierrc. [src5]
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2,
"endOfLine": "lf"
}
Verify: npx prettier --check src/ → All matched files use Prettier code style!
4. Add npm scripts
Add convenience scripts to package.json. [src1]
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"format:check": "prettier --check .",
"check": "eslint . && prettier --check ."
}
}
Code Examples
Flat Config with React + TypeScript
// eslint.config.mjs — React + TypeScript project
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import eslintConfigPrettier from "eslint-config-prettier";
import reactPlugin from "eslint-plugin-react";
import reactHooksPlugin from "eslint-plugin-react-hooks";
import globals from "globals";
export default tseslint.config(
{ ignores: ["dist/", "build/", "node_modules/"] },
eslint.configs.recommended,
...tseslint.configs.recommended,
{
files: ["**/*.{ts,tsx}"],
plugins: { react: reactPlugin, "react-hooks": reactHooksPlugin },
languageOptions: { globals: { ...globals.browser } },
settings: { react: { version: "detect" } },
rules: {
"react/react-in-jsx-scope": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
},
},
eslintConfigPrettier,
);
Flat Config with Node.js Backend
// eslint.config.mjs — Node.js + TypeScript backend
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import eslintConfigPrettier from "eslint-config-prettier";
import globals from "globals";
export default tseslint.config(
{ ignores: ["dist/", "node_modules/"] },
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
globals: { ...globals.node },
parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname },
},
rules: {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-promises": "error",
},
},
eslintConfigPrettier,
);
Anti-Patterns
Wrong: Putting eslint-config-prettier before other configs
// ❌ BAD — Prettier config is overridden by later configs
export default [
eslintConfigPrettier, // Too early!
eslint.configs.recommended, // Re-enables formatting rules
];
Correct: eslint-config-prettier always last
// ✅ GOOD — Prettier config last, disables all formatting rules
export default [
eslint.configs.recommended,
...tseslint.configs.recommended,
eslintConfigPrettier, // Last
];
Wrong: Mixing ESLint formatting rules with Prettier
// ❌ BAD — ESLint formatting rules conflict with Prettier
{ rules: { "semi": ["error", "never"], "quotes": ["error", "double"] } }
Correct: Let Prettier handle all formatting
// ✅ GOOD — Only logic rules in ESLint, formatting in .prettierrc
{ rules: { "no-console": "warn", "prefer-const": "error" } }
Common Pitfalls
- Config file not found: ESLint 9 only looks for
eslint.config.*. Fix: rename.eslintrc.*. [src7] - Globals undefined: Flat config does not auto-include globals. Fix:
npm install globalsand add tolanguageOptions. [src1] - Plugin not compatible: Older plugins lack flat config support. Fix: use
@eslint/compat. [src7] - TypeScript files not linted: Missing typescript-eslint. Fix: ensure
typescript-eslintis in the config array. [src2] - Prettier and ESLint disagree: Conflicting rules. Fix: run
npx eslint-config-prettier src/index.ts. [src3] - Type-checked rules slow: Full type-check on lint. Fix: use
projectService: truefor faster resolution. [src2] - CI fails but local passes: Version differences. Fix: pin versions and use
npm ci. [src1]
Diagnostic Commands
# Check ESLint version
npx eslint --version
# Print resolved config for a specific file
npx eslint --print-config src/index.ts
# Find rules conflicting with Prettier
npx eslint-config-prettier src/index.ts
# Check Prettier version
npx prettier --version
# Test Prettier formatting on a single file
npx prettier --check src/index.ts
Version History & Compatibility
| Version | Status | Breaking Changes | Migration Notes |
|---|---|---|---|
| ESLint 9.x | Current | Flat config default, .eslintrc deprecated | Use eslint.config.mjs |
| typescript-eslint 8.x | Current | Single package, flat config API | Replace @typescript-eslint/* with typescript-eslint |
| Prettier 3.x | Current | ESM-only, async API | — |
| ESLint 8.x | Maintenance | — | Migrate to 9 |
When to Use / When Not to Use
| Use When | Don't Use When | Use Instead |
|---|---|---|
| JavaScript/TypeScript projects | Using Biome for both linting + formatting | Biome (biomejs.dev) |
| Need granular rule control | Deno projects (built-in linter) | deno lint + deno fmt |
| Team needs enforced code style | Tiny scripts or one-off files | Manual review |
Important Caveats
- ESLint 9.x
defineConfigandextendswere added in ESLint 9.15+ — older 9.x releases lack this convenience API eslint-plugin-prettierreports formatting issues as ESLint errors, which can be confusing- Type-aware linting adds 3-10x overhead — consider using it only in CI
- The
globalsnpm package must be installed separately in flat config