DeepFrontend
Practice ArenaBlogSign in
Go Pro
DeepFrontend

Interview-grade learning paths and hands-on practice for mid-to-senior engineers. Master internals, patterns, and system architecture with runnable code.

All systems operational

Core Courses

  • -JavaScript Internals
  • -React Reconciliation
  • -TypeScript rigor
  • -Next.js Caching
  • -Node.js Event Loop
  • -System Design
  • -Web Security
  • -CSS & Page Layouts

Explore

  • Learning Paths
  • Practice Arena
  • Pricing Options
  • HTML Sitemap

Resources

  • Privacy Policy
  • Terms of Service
  • Email Support

© 2026 DeepFrontend. All rights reserved.

Expert learning environments for web engineering teams.

Home/Foundations & Tooling/Linting & Formatting (ESLint, Prettier)
beginner15 min read·Updated Dec 2024Expert reviewed

Linting & Formatting (ESLint, Prettier)

ESLint catches bugs and enforces code quality; Prettier enforces formatting. They solve different problems and work together. A properly configured lint + format setup runs automatically on save, on commit, and in CI — and eliminates entire classes of review comments.

eslintprettierlintingformattingcode-qualitypre-commithusky

Knowledge Check

2 questions · pass at 70%

0/2
mediummcq

1. What is the purpose of `eslint-config-prettier`?


Cheatsheet

Download-ready reference
Cheatsheet
ESLint     static analysis — catches bugs, enforces patterns
Prettier   opinionated formatter — removes formatting decisions
Together   ESLint for quality + Prettier for style. Never debate tabs vs spaces again.

Setup:
  npm install -D eslint prettier eslint-config-prettier
  + typescript-eslint (for TS)
  + eslint-plugin-react + eslint-plugin-react-hooks (for React)

eslint.config.mjs (flat config, ESLint 9+):
  import prettier from 'eslint-config-prettier';
  export default [...yourRules, prettier];  // prettier must be last

.prettierrc.json:
  { "semi": true, "singleQuote": true, "tabWidth": 2, "trailingComma": "es5" }

Rule severities:
  'error'  CI fails, commit blocked
  'warn'   shown but doesn't fail (use --max-warnings 0 in CI to enforce)
  'off'    disabled

Pre-commit automation:
  husky    installs Git hooks
  lint-staged  runs tools on staged files only
  Workflow: git commit → husky → lint-staged → eslint --fix + prettier --write → commit

CI:
  npx eslint . --max-warnings 0   fail on any warning
  npx prettier --check .          fail if any file is unformatted

Related topics

Package Managers (npm / yarn / pnpm)Git & Version ControlBuild Tools (Vite, Webpack, esbuild, Rollup, Turbopack)Pro

On this page

15m
Knowledge CheckCheatsheet

Concept#

ESLint — code quality and bug prevention#

ESLint is a static analysis tool that finds problems in your JavaScript/TypeScript. It reads your code without running it and reports violations of configurable rules.

What ESLint catches:

  • Actual bugs: unused variables, unreachable code, missing await, == vs ===
  • Code quality: complexity, naming conventions, import order
  • Security: eval(), dangerouslySetInnerHTML misuse
  • React-specific: missing dependency arrays in hooks, key prop violations

What ESLint doesn't catch: formatting (indentation, quotes, semicolons) — that's Prettier's job.

ESLint flat config (modern)

ESLint v9 introduced a new "flat config" format. This is what new projects should use:

// eslint.config.mjs
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import reactPlugin from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
 
export default [
  js.configs.recommended,
  ...tseslint.configs.recommended














ESLint rule severities

'off'   or 0  — disabled
'warn'  or 1  — violation shown as warning (CI can still pass)
'error' or 2  — violation shown as error (CI fails)

Use 'error' for bugs and security issues. Use 'warn' for style suggestions you want to migrate toward. Don't leave 'warn' rules forever — they accumulate and become noise.

Prettier — opinionated formatting#

Prettier reformats your code to a consistent style. The key insight: Prettier removes all formatting decisions. There's no "tabs vs spaces" debate — Prettier decides and enforces.

Prettier handles: indentation, quotes (single/double), semicolons, trailing commas, line length, bracket spacing, arrow function parens.

Prettier does NOT handle: code logic, variable names, import order — that's ESLint.

// .prettierrc.json
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100,
  "arrowParens": "always"
}
npx prettier --write src/**/*.ts   # format all TypeScript files
npx prettier --check src/**/*.ts   # check without writing (CI mode)

Prettier + ESLint integration

They overlap on some rules (quotes, semicolons). The solution: disable ESLint's formatting rules and let Prettier handle them.

npm install -D eslint-config-prettier
// eslint.config.mjs — add prettier at the end (overrides conflicting rules)
import prettier from 'eslint-config-prettier';
 
export default [
  ...tseslint.configs.recommended,
  // ... your rules
  prettier,  // must be last — disables ESLint formatting rules
];

Pre-commit hooks with lint-staged + husky#

The best time to catch lint/format errors is before they're committed — not in CI 5 minutes later.

husky installs Git hooks. lint-staged runs tools only on staged files (fast — not the whole codebase).

npm install -D husky lint-staged
npx husky init
// package.json
{
  "lint-staged": {
    "*.{ts,tsx}": ["eslint --fix", "prettier --write"],
    "*.{json,md,css}": ["prettier --write"]
  }
}
# .husky/pre-commit
npx lint-staged

Now every git commit runs ESLint + Prettier on staged files. Violations block the commit.

CI enforcement#

Pre-commit hooks can be bypassed with git commit --no-verify. CI is the final gate.

# .github/workflows/lint.yml
- run: npx eslint . --max-warnings 0
- run: npx prettier --check .

--max-warnings 0 makes warnings fail the build. This forces warnings to be either fixed or explicitly promoted to errors.


Common Mistakes#

1. Running ESLint + Prettier on the whole project in pre-commit hooks#

Slow on large projects. lint-staged fixes this — it runs only on staged files.

2. Conflicting Prettier and ESLint rules without eslint-config-prettier#

You get prettier/prettier: error on every formatted file. Always add eslint-config-prettier as the last config entry.

3. Ignoring lint warnings in CI#

eslint . --max-warnings 100 lets 100 warnings accumulate. They become permanent noise. Use --max-warnings 0 or fix/convert them to errors.

4. Not adding .eslintignore / ignores for generated files#

ESLint on node_modules, dist, or generated files is wasted CPU. Always ignore them:

// eslint.config.mjs
export default [
  { ignores: ['dist/**', 'node_modules/**', '*.generated.ts'] },
  // ...
];

5. Installing ESLint plugins without the corresponding config#

Plugins only register rules; they don't enable them. You need both the plugin AND the config/recommended rules.


Best Practices#

  • Autofix on save in your editor: VS Code: "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" } + Prettier format on save.
  • Use eslint --fix in lint-staged: automatically fixes fixable issues (avoids trivial "fix trailing comma" commits).
  • Start with recommended configs then add project-specific rules. Don't write rules from scratch.
  • Pin ESLint and Prettier versions — formatting changes between Prettier minor versions can cause mass reformatting commits if different team members run different versions.

,
{
files: ['**/*.{ts,tsx}'],
plugins: {
react: reactPlugin,
'react-hooks': reactHooks,
},
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
},
];