Tooling5 min read

Linting & Code Formatting

Configure ESLint and Prettier for zero-friction code quality: flat config, shared configs, pre-commit hooks, and editor integration.

eslintprettiertoolingcode-quality

ESLint (linting) and Prettier (formatting) eliminate style debates and catch common errors automatically. When configured correctly, they run silently in the editor, on save, and in CI-producing consistent code without manual effort.

Prettier owns formatting-no ESLint formatting rules. ESLint catches logic and quality issues. Autofix everything fixable. Enforce via pre-commit hooks so nothing bad reaches the remote. Share configs across monorepo packages.

Workflow

  1. Configure ESLint flat config (v9+)ESLint flat config replaces `.eslintrc` - it's simpler, more explicit, and will be the only supported format going forward.
  2. Configure Prettier independentlyPrettier is opinionated and intentionally limited - fighting it wastes time. Accept its choices.
  3. Add lint-staged and Husky for pre-commit enforcementPre-commit hooks prevent linting errors from ever reaching the repository.
  4. Create shared configs for monoreposDuplicating ESLint/Prettier configs across packages leads to drift; a shared package enforces consistency.
  5. Integrate with editors and CIEditor integration provides real-time feedback; CI catches what slips through.

Output Format

ESLint flat config with TypeScript rules, Prettier config, lint-staged pre-commit hook, shared monorepo configs, CI linting gate, editor settings.

Examples

eslint.config.mjs: `export default tseslint.config(eslint.recommended, ...tseslint.recommendedTypeChecked, prettierConfig, { languageOptions: { parserOptions: { projectService: true } }, rules: { "@typescript-eslint/no-floating-promises": "error" } })`
lint-staged: `{ "*.{ts,tsx}": ["eslint --fix --max-warnings=0", "prettier --write"], "*.{json,md,css}": "prettier --write" }`
CI step: `- run: npx eslint . --max-warnings 0 && npx prettier --check .`

Edge Cases & Gotchas

  • ESLint and Prettier conflicts: always add eslint-config-prettier LAST; if conflicts remain, a rule is not covered by it - add it manually to ESLint config
  • Auto-fix breaking logic: `--fix` can theoretically alter code semantics (rare); review auto-fixed changes in the pre-commit stage via `git diff --cached`
  • Monorepo ESLint: each package needs its own `eslint.config.mjs` extending the shared config to pick up package-specific plugins (e.g., Next.js rules only in the Next.js app)

When to Break These Rules

  • Disable specific rules for generated files (protobuf output, GraphQL types): add file patterns to `.eslintignore` or use `/* eslint-disable */` at the top of generated files.

Reference Files

  • ESLint flat config: https://eslint.org/docs/latest/use/configure/configuration-files-new
  • typescript-eslint: https://typescript-eslint.io/
  • Prettier: https://prettier.io/
  • Husky: https://typicode.github.io/husky/

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.