---
# === IDENTITY ===
id: software/devops/eslint-prettier-config/2026
canonical_question: "ESLint + Prettier configuration reference"
aliases:
  - "How to configure ESLint 9 with Prettier using flat config"
  - "ESLint Prettier integration setup guide"
  - "eslint.config.js with prettier and typescript-eslint"
  - "ESLint flat config TypeScript Prettier best practices"
entity_type: software_reference
domain: software > devops > ESLint + Prettier Configuration
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === VERIFICATION ===
last_verified: 2026-02-28
confidence: 0.93
version: 1.0
first_published: 2026-02-28

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: stable
  last_breaking_change: "ESLint 9.0 (April 2024) — flat config became default, .eslintrc deprecated"
  next_review: 2026-08-27
  change_sensitivity: medium

# === CONSTRAINTS ===
constraints:
  - "ESLint 9+ requires flat config (eslint.config.js/mjs/cjs) — .eslintrc.* files are deprecated and ignored by default"
  - "eslint-config-prettier MUST be the last item in the config array to correctly disable conflicting formatting rules"
  - "Never use eslint-plugin-prettier and manual formatting rules simultaneously — they will conflict"
  - "typescript-eslint v8+ 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"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "Using Biome instead of ESLint + Prettier"
    use_instead: "Biome official documentation at biomejs.dev"
  - condition: "Still on ESLint 8 with .eslintrc"
    use_instead: "ESLint migration guide at eslint.org/docs/latest/use/configure/migration-guide"

# === AGENT HINTS ===
inputs_needed:
  - key: "language"
    question: "Are you using TypeScript or JavaScript?"
    type: choice
    options: ["TypeScript", "JavaScript"]
  - key: "framework"
    question: "Which framework are you using?"
    type: choice
    options: ["React", "Vue", "Angular", "Node.js", "None"]
  - key: "module_type"
    question: "Is your project using ESM or CommonJS?"
    type: choice
    options: ["ESM (type: module)", "CommonJS"]

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/software/devops/eslint-prettier-config/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-02-28)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "software/devops/typescript-tsconfig/2026"
      label: "TypeScript tsconfig Patterns Reference"
    - id: "software/devops/pre-commit-hooks/2026"
      label: "Pre-commit Hooks Setup Reference"
    - id: "software/devops/vite-configuration/2026"
      label: "Vite Configuration Reference"
  solves: []
  alternative_to: []
  often_confused_with: []

# === SOURCES ===
sources:
  - id: src1
    title: "Configuration Files — ESLint Official Docs"
    author: ESLint
    url: https://eslint.org/docs/latest/use/configure/configuration-files
    type: official_docs
    published: 2024-04-05
    reliability: authoritative
  - id: src2
    title: "Getting Started — typescript-eslint"
    author: typescript-eslint
    url: https://typescript-eslint.io/getting-started/
    type: official_docs
    published: 2024-07-01
    reliability: authoritative
  - id: src3
    title: "eslint-config-prettier — GitHub"
    author: Prettier
    url: https://github.com/prettier/eslint-config-prettier
    type: official_docs
    published: 2024-01-15
    reliability: high
  - id: src4
    title: "eslint-plugin-prettier — GitHub"
    author: Prettier
    url: https://github.com/prettier/eslint-plugin-prettier
    type: official_docs
    published: 2024-01-15
    reliability: high
  - id: src5
    title: "Prettier Configuration Options"
    author: Prettier
    url: https://prettier.io/docs/en/options
    type: official_docs
    published: 2024-06-01
    reliability: authoritative
  - id: src6
    title: "Evolving flat config with extends"
    author: ESLint
    url: https://eslint.org/blog/2025/03/flat-config-extends-define-config-global-ignores/
    type: official_docs
    published: 2025-03-14
    reliability: high
  - id: src7
    title: "Configuration Migration Guide — ESLint"
    author: ESLint
    url: https://eslint.org/docs/latest/use/configure/migration-guide
    type: official_docs
    published: 2024-04-05
    reliability: authoritative
---

# ESLint + Prettier Configuration Reference

## TL;DR

- **Bottom line**: Use ESLint 9 flat config (`eslint.config.mjs`) with `typescript-eslint` v8 for linting and Prettier as a separate formatter; connect them via `eslint-config-prettier` as the last config entry.
- **Key tool/command**: `npx eslint . && npx prettier --check .`
- **Watch out for**: Putting `eslint-config-prettier` anywhere except last in the config array — formatting rules from other configs will leak through and conflict with Prettier.
- **Works with**: ESLint 9.x, typescript-eslint 8.x, Prettier 3.x, Node.js 18+.

## Constraints
<!-- Agents: read this section before recommending any action from this unit.
     These are hard constraints that must not be violated. -->

- ESLint 9+ requires flat config (`eslint.config.js`/`.mjs`/`.cjs`) — `.eslintrc.*` files are deprecated and ignored by default
- `eslint-config-prettier` MUST be the last item in the config array to correctly disable conflicting formatting rules
- Never use `eslint-plugin-prettier` and manual formatting rules simultaneously — they will conflict
- `typescript-eslint` v8+ 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` or `prettier.config.mjs` | Formatting options |
| Ignore file | `.prettierignore` | Files Prettier should skip |
| TypeScript parser | `typescript-eslint/parser` | Built into `typescript-eslint` v8 |
| 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 ↓
├── Using Vue?
│   ├── YES → Add eslint-plugin-vue
│   └── NO ↓
├── Need type-aware rules (e.g., no-floating-promises)?
│   ├── YES → Use tseslint.configs.recommendedTypeChecked + parserOptions.project
│   └── NO → Use tseslint.configs.recommended (faster, no type info)
└── 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]

```bash
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. The `.mjs` extension ensures ESM syntax works regardless of your `package.json` type field. [src2]

```javascript
// eslint.config.mjs
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import eslintConfigPrettier from "eslint-config-prettier";

export default tseslint.config(
  // Global ignores (replaces .eslintignore)
  { ignores: ["dist/", "node_modules/", "coverage/", "*.config.mjs"] },

  // Base ESLint recommended rules
  eslint.configs.recommended,

  // TypeScript recommended rules (type-unaware — fast)
  ...tseslint.configs.recommended,

  // Project-specific overrides
  {
    files: ["**/*.ts", "**/*.tsx"],
    rules: {
      "@typescript-eslint/no-unused-vars": ["error", {
        argsIgnorePattern: "^_",
        varsIgnorePattern: "^_",
      }],
      "@typescript-eslint/no-explicit-any": "warn",
      "@typescript-eslint/consistent-type-imports": "error",
    },
  },

  // Prettier MUST be last — disables all formatting rules
  eslintConfigPrettier,
);
```

**Verify**: `npx eslint --print-config src/index.ts | grep semi` → should show no `semi` rule (disabled by Prettier config)

### 3. Create Prettier configuration

Define formatting preferences. Prettier has sensible defaults — only override what you need. [src5]

```json
// .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100,
  "tabWidth": 2,
  "arrowParens": "always",
  "endOfLine": "lf"
}
```

**Verify**: `npx prettier --check src/` → expected: `All matched files use Prettier code style!`

### 4. Create ignore files

Prevent linting and formatting of generated files. [src1]

```bash
# .prettierignore
dist/
node_modules/
coverage/
*.min.js
pnpm-lock.yaml
package-lock.json
```

**Verify**: `npx prettier --check .` should skip listed directories

### 5. Add npm scripts

Add convenience scripts to `package.json`. [src1]

```json
{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix",
    "format": "prettier --write .",
    "format:check": "prettier --check .",
    "check": "eslint . && prettier --check ."
  }
}
```

**Verify**: `npm run check` → runs both linting and format checking

### 6. Configure type-aware linting (optional)

For rules that need type information (e.g., `@typescript-eslint/no-floating-promises`), enable type-checked mode. This is slower but catches more bugs. [src2]

```javascript
// eslint.config.mjs — type-aware variant
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.recommendedTypeChecked,
  {
    languageOptions: {
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
  },
  eslintConfigPrettier,
);
```

**Verify**: `npx eslint src/` → type-aware rules now active

## Code Examples

### Flat Config with React + TypeScript

> Full script: [flat-config-with-react-typescript.js](scripts/flat-config-with-react-typescript.js) (29 lines)

```javascript
// 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";
# ... (see full script)
```

### Flat Config with Node.js Backend

> Full script: [flat-config-with-node-js-backend.js](scripts/flat-config-with-node-js-backend.js) (28 lines)

```javascript
// 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";
# ... (see full script)
```

### Using eslint-plugin-prettier (single-command approach)

```javascript
// eslint.config.mjs — Prettier as an ESLint rule
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";

export default tseslint.config(
  { ignores: ["dist/", "node_modules/"] },
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  // This single import sets up both eslint-plugin-prettier AND eslint-config-prettier
  eslintPluginPrettierRecommended,
);
```

## Anti-Patterns

### Wrong: Putting eslint-config-prettier before other configs

```javascript
// ❌ BAD — Prettier config is overridden by later configs
export default [
  eslintConfigPrettier,           // Too early! Gets overridden
  eslint.configs.recommended,     // Re-enables formatting rules
  ...tseslint.configs.recommended,
];
```

### Correct: eslint-config-prettier always last

```javascript
// ✅ GOOD — Prettier config last, disables all formatting rules
export default [
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  eslintConfigPrettier,           // Last — overrides formatting rules
];
```

### Wrong: Mixing ESLint formatting rules with Prettier

```javascript
// ❌ BAD — ESLint formatting rules conflict with Prettier
export default [
  eslint.configs.recommended,
  {
    rules: {
      "semi": ["error", "never"],     // Conflicts with Prettier
      "quotes": ["error", "double"],  // Conflicts with Prettier
      "indent": ["error", 4],         // Conflicts with Prettier
    },
  },
  eslintConfigPrettier,
];
```

### Correct: Let Prettier handle all formatting

```javascript
// ✅ GOOD — Only logic rules in ESLint, formatting in .prettierrc
export default [
  eslint.configs.recommended,
  {
    rules: {
      "no-console": "warn",           // Logic rule — ESLint's job
      "no-debugger": "error",         // Logic rule — ESLint's job
      "prefer-const": "error",        // Logic rule — ESLint's job
    },
  },
  eslintConfigPrettier,
];
// Formatting (semi, quotes, indent) goes in .prettierrc
```

### Wrong: Using typescript-eslint v7 with ESLint 9

```bash
# ❌ BAD — v7 does not support flat config
npm install --save-dev @typescript-eslint/parser@7 @typescript-eslint/eslint-plugin@7
```

### Correct: Using typescript-eslint v8 unified package

```bash
# ✅ GOOD — v8 has flat config support via single package
npm install --save-dev typescript-eslint@^8
```

## Common Pitfalls

- **Config file not found**: ESLint 9 only looks for `eslint.config.*` files — rename `.eslintrc.*` to `eslint.config.mjs`. Fix: `mv .eslintrc.json eslint.config.mjs` and convert format. [src7]
- **Globals undefined error**: Flat config does not auto-include `browser` or `node` globals. Fix: `npm install globals` and add `languageOptions: { globals: { ...globals.browser } }`. [src1]
- **Plugin not compatible**: Some older ESLint plugins do not support flat config. Fix: wrap with `@eslint/compat` — `import { fixupPluginRules } from "@eslint/compat"`. [src7]
- **TypeScript files not linted**: ESLint does not lint `.ts`/`.tsx` by default without typescript-eslint. Fix: ensure `typescript-eslint` is in the config array. [src2]
- **Prettier and ESLint disagree on formatting**: Conflicting rules still active. Fix: run `npx eslint-config-prettier src/index.ts` to find conflicting rules. [src3]
- **Type-checked rules extremely slow**: `parserOptions.project` causes full type-check on every lint. Fix: use `projectService: true` (new in typescript-eslint v8) for faster resolution. [src2]
- **CI fails but local passes**: Different ESLint/Prettier versions. Fix: pin exact versions in `package.json` and use `npm ci` in CI. [src1]

## Diagnostic Commands

```bash
# 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

# Run ESLint with debug output
DEBUG=eslint:* npx eslint src/

# Check Prettier version
npx prettier --version

# Test Prettier formatting on a single file
npx prettier --check src/index.ts

# Show what Prettier would change
npx prettier --write --list-different src/
```

## Version History & Compatibility

| Version | Status | Breaking Changes | Migration Notes |
|---|---|---|---|
| ESLint 9.x | Current | Flat config default, .eslintrc deprecated | Use `eslint.config.mjs`; `@eslint/compat` for old plugins |
| typescript-eslint 8.x | Current | Single `typescript-eslint` package, flat config API | Replace `@typescript-eslint/parser` + `@typescript-eslint/eslint-plugin` with `typescript-eslint` |
| Prettier 3.x | Current | ESM-only, async API | Use `--write` instead of deprecated `--write .` |
| ESLint 8.x | Maintenance | — | Still works with `.eslintrc.*` but migrate to 9 |
| typescript-eslint 7.x | EOL | — | No flat config support; upgrade to v8 |

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| JavaScript/TypeScript projects of any size | Using Biome for both linting + formatting | Biome (biomejs.dev) |
| Need granular rule control and plugin ecosystem | Deno projects (built-in linter) | `deno lint` + `deno fmt` |
| Team needs enforced code style + quality | Tiny scripts or one-off files | Manual review |
| CI pipeline requires automated checks | Already using Rome/Biome and satisfied | Keep Biome |

## Important Caveats

- ESLint 9.x `defineConfig` and `extends` were added in ESLint 9.15+ — older 9.x releases lack this convenience API
- `eslint-plugin-prettier` reports formatting issues as ESLint errors, which can be confusing — most teams prefer running them separately
- Type-aware linting (`recommendedTypeChecked`) adds 3-10x overhead — consider using it only in CI, not in editor
- The `globals` npm package must be installed separately in flat config — it is not bundled with ESLint

## Related Units

- [TypeScript tsconfig Patterns Reference](/software/devops/typescript-tsconfig/2026)
- [Pre-commit Hooks Setup Reference](/software/devops/pre-commit-hooks/2026)
- [Vite Configuration Reference](/software/devops/vite-configuration/2026)
