Introduction
If you've ever worked on a JavaScript or TypeScript project with more than one developer, you've probably encountered the eternal debate: tabs vs spaces, semicolons vs no semicolons, single quotes vs double quotes. These arguments can derail entire code reviews. That's where Prettier and ESLint come in — two tools that solve related but fundamentally different problems.
Many developers confuse Prettier and ESLint or assume they do the same thing. In reality, they complement each other beautifully when configured correctly — but can cause frustrating conflicts when set up poorly. This guide will walk you through exactly what each tool does, how they differ, how to configure them individually and together, and how to avoid the most common pitfalls.
Whether you're setting up a brand-new project or untangling a messy existing configuration, this article has everything you need. If you'd like to experiment with code formatting in your browser first, try our JavaScript Formatter tool.
What is Prettier?
Prettier is an opinionated code formatter. Its sole job is to take your code and reprint it in a consistent style. It doesn't care whether your code is correct, efficient, or follows best practices — it only cares about how it looks.
Prettier supports a wide range of languages including JavaScript, TypeScript, HTML, CSS, JSON, GraphQL, Markdown, and YAML. When you run Prettier, it parses your code into an abstract syntax tree (AST) and then reprints it from scratch according to its formatting rules.
Key Characteristics of Prettier
- Opinionated by design — Prettier intentionally limits configuration options. This forces teams to stop arguing about style and accept a consistent default.
- Deterministic output — Given the same input and configuration, Prettier always produces the same output regardless of the original formatting.
- AST-based — Prettier parses your code into an AST and reprints it, meaning it understands the structure of your code rather than applying regex-based find-and-replace.
- Multi-language — One tool handles JavaScript, TypeScript, CSS, HTML, JSON, and more.
- Zero-config by default — Prettier works out of the box with sensible defaults. You can override a small set of options if needed.
What Prettier Handles
- Indentation (tabs or spaces, and how many)
- Line length and wrapping
- Semicolons (add or remove)
- Quote style (single or double)
- Trailing commas
- Bracket spacing
- JSX quote style
- End-of-line characters
What is ESLint?
ESLint is a static analysis tool (linter) for JavaScript and TypeScript. Its primary job is to find and report patterns in your code that are likely bugs, violate best practices, or don't conform to your team's coding standards. While ESLint also has some formatting rules, its core strength is code quality analysis.
ESLint works by parsing your code and running a set of configurable rules against the resulting AST. Each rule can be turned off, set to warn, or set to error. Many rules also come with auto-fix capabilities.
Key Characteristics of ESLint
- Highly configurable — Hundreds of built-in rules, plus thousands of community plugins.
-
Catches real bugs — Rules like
no-unused-vars,no-undef, andeqeqeqcatch actual programming errors. -
Enforces best practices — Rules like
no-eval,no-implicit-globals, andprefer-constencourage better code. - Extensible via plugins — Plugins for React, Vue, TypeScript, accessibility, testing libraries, and more.
-
Auto-fixable — Many rules can automatically fix issues with
--fix.
What ESLint Handles
- Unused variables and imports
- Undefined variables
- Unreachable code
- Type coercion issues (
==vs===) - Missing return statements
- React hooks rules (with plugin)
- Accessibility issues (with plugin)
- Import ordering and resolution
- Naming conventions
Key Differences: Formatting vs Linting
The fundamental difference comes down to this: Prettier handles how your code looks; ESLint handles how your code works.
| Aspect | Prettier | ESLint |
|---|---|---|
| **Primary purpose** | Code formatting | Code quality & bug detection |
| **Configuration** | Minimal (intentionally) | Extensive (hundreds of rules) |
| **Auto-fix** | Always rewrites entire file | Fixes only specific rule violations |
| **Languages** | JS, TS, HTML, CSS, JSON, etc. | JS, TS (with parser) |
| **Catches bugs** | No | Yes |
| **Enforces style** | Yes (formatting only) | Yes (code patterns & some formatting) |
| **Opinioned** | Very (by design) | Configurable |
| **Plugin ecosystem** | Small (language parsers) | Huge (React, Vue, a11y, etc.) |
An Analogy
Think of it like writing an essay. Prettier is like a typesetter — it ensures consistent margins, font sizes, and paragraph spacing. ESLint is like a grammar checker and editor — it catches spelling errors, run-on sentences, and logical inconsistencies. You need both for a polished final product.
Configuration Examples
Prettier Configuration (.prettierrc)
Prettier's configuration is intentionally minimal. Create a .prettierrc file in your project root. You can format JSON config files easily with our JSON Formatter.
You can also use a .prettierrc.js file for JavaScript-based configuration:
Prettier Ignore File (.prettierignore)
Create a .prettierignore to exclude files from formatting:
node_modules
dist
build
coverage
*.min.js
package-lock.json
ESLint Configuration (.eslintrc.json)
ESLint's configuration is far more extensive. Here's a solid starting point for a modern JavaScript/TypeScript project:
ESLint for TypeScript
For TypeScript projects, you'll need the TypeScript parser and plugin:
ESLint for React
React projects benefit from additional plugins:
Using Prettier and ESLint Together
This is where most developers run into trouble. Both Prettier and ESLint have opinions about formatting, and when their opinions clash, you get an endless loop of conflicting fixes. The solution is eslint-config-prettier.
The Problem
ESLint has formatting rules like indent, quotes, and semi. Prettier also controls indentation, quotes, and semicolons. If ESLint says "use double quotes" but Prettier says "use single quotes," every save triggers a conflict. ESLint auto-fix changes them to double quotes, then Prettier changes them back to single quotes.
The Solution: eslint-config-prettier
The eslint-config-prettier package disables all ESLint rules that conflict with Prettier. This way, ESLint handles code quality while Prettier handles formatting with zero overlap.
Step-by-Step Setup
Step 1: Install dependencies
npm install --save-dev prettier eslint eslint-config-prettier
Step 2: Configure ESLint to use eslint-config-prettier
Add "prettier" as the last item in your extends array. This is critical — it must be last so it overrides any conflicting rules from other configs:
Step 3: Configure Prettier
Create your .prettierrc:
Step 4: Add scripts to package.json
ESLint Flat Config (eslint.config.js)
If you're using the newer ESLint flat config format (ESLint v9+), here's the equivalent setup:
Common Conflicts and Fixes
Even with eslint-config-prettier, teams still run into issues. Here are the most common problems and their solutions.
Conflict 1: "prettier" Not Last in Extends
Symptom: ESLint and Prettier fight over formatting on every save.
Fix: Ensure "prettier" is the absolute last entry in your extends array. If you add a plugin after it, that plugin's formatting rules will override the disable.
Conflict 2: ESLint Formatting Rules Still Active
Symptom: ESLint reports errors on formatting issues that Prettier should handle.
Fix: Run the eslint-config-prettier CLI helper to check for conflicts:
npx eslint-config-prettier .eslintrc.json
This command lists any ESLint rules that conflict with Prettier so you can disable them manually.
Conflict 3: Different Line Endings (CRLF vs LF)
Symptom: Prettier reformats every line in a file, or Git shows changes on lines that look identical.
Fix: Set "endOfLine": "lf" in your .prettierrc and configure Git:
git config --global core.autocrlf input
Also add an .editorconfig file:
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2
Conflict 4: HTML/JSX Attribute Formatting
Symptom: Prettier wraps JSX attributes differently than expected, and ESLint complains about the result.
Fix: This is usually caused by having react/jsx-max-props-per-line or similar ESLint rules still enabled. With eslint-config-prettier, these should be disabled automatically. If not, disable them manually:
Conflict 5: Import Order
Symptom: Prettier and an ESLint import sorting plugin fight over import order.
Fix: Prettier does not sort imports by default. If you want sorted imports, use eslint-plugin-import with the import/order rule, or use the @trivago/prettier-plugin-sort-imports Prettier plugin — but do not use both simultaneously.
Editor Integration
Proper editor integration is what makes these tools truly powerful. Instead of running commands manually, your editor formats and lints as you work.
VS Code Setup
Install the following extensions:
- Prettier - Code formatter (esbenp.prettier-vscode)
- ESLint (dbaeumer.vscode-eslint)
Then configure your .vscode/settings.json:
This configuration means: on save, ESLint auto-fixes code quality issues first, then Prettier formats the file. The order matters — ESLint fixes should happen before Prettier formatting to avoid conflicts.
WebStorm / JetBrains IDEs
- Go to Settings > Languages & Frameworks > JavaScript > Prettier
- Check "On save" and "On Reformat Code action"
- ESLint is automatically detected from your project's config
Neovim Setup
If you use Neovim with LSP, configure null-ls or conform.nvim for Prettier and use nvim-lspconfig for ESLint:
CI/CD Setup
Running Prettier and ESLint in your CI/CD pipeline ensures that no unformatted or problematic code reaches your main branch.
GitHub Actions Example
name: Lint and Format Check
on:
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- name: Check formatting
run: npx prettier --check .
- name: Run linter
run: npx eslint . --ext .js,.jsx,.ts,.tsx
Note the use of prettier --check instead of prettier --write in CI. The --check flag exits with a non-zero code if any file isn't formatted, without actually modifying files.
Pre-commit Hooks with Husky and lint-staged
For catching issues before they even reach CI, set up pre-commit hooks:
npm install --save-dev husky lint-staged
npx husky init
Add to your package.json:
Update the Husky pre-commit hook at .husky/pre-commit:
npx lint-staged
This runs ESLint and Prettier only on the files you've staged for commit, keeping your hook fast even in large repositories.
When to Use Each Tool
Use Prettier When...
- You want consistent formatting across your entire codebase with zero debate
- You're formatting non-JavaScript files like JSON, CSS, HTML, Markdown, or YAML
- You want a zero-config or minimal-config solution
- You're tired of formatting discussions in code reviews
- You need deterministic output regardless of input formatting
Use ESLint When...
- You want to catch bugs and enforce coding best practices
- You need framework-specific rules (React hooks, Vue composition API, etc.)
- You want to enforce naming conventions or import ordering
- You need custom rules specific to your project or organization
- You want to gradually improve code quality with warnings before enforcing errors
Use Both Together When...
- You want the best of both worlds — which is most projects
- You want Prettier to handle all formatting and ESLint to handle all code quality
- You're working on a team and want to eliminate both style debates and common bugs
- You're building a production application that needs to meet quality standards
Summary Decision Table
| Scenario | Recommendation |
|---|---|
| Solo hobby project | Prettier alone is often enough |
| Small team, JS/TS project | Both with eslint-config-prettier |
| Large enterprise codebase | Both, plus custom ESLint plugins |
| Non-JS files only (CSS, JSON, MD) | Prettier only |
| Legacy project with no formatting | Add Prettier first, then ESLint gradually |
Advanced Tips
Per-file Overrides
Both tools support per-file configuration overrides. In ESLint:
In Prettier, use the overrides field in .prettierrc:
Disabling Rules Inline
Sometimes you need to disable a rule for a specific line or block. ESLint supports inline comments:
// eslint-disable-next-line no-console
console.log('Debug info');
/* eslint-disable no-unused-vars */
const reservedForLater = true;
/* eslint-enable no-unused-vars */
For Prettier, use prettier-ignore comments:
// prettier-ignore
const matrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
];
Migrating a Large Codebase
If you're adding Prettier to an existing project, format everything at once in a single commit. This creates a clear boundary in your Git history. Use git blame --ignore-rev to tell Git to skip that formatting commit when assigning blame:
# Format everything
npx prettier --write .
# Commit the formatting change
git add -A
git commit -m "chore: apply prettier formatting"
# Add the commit hash to .git-blame-ignore-revs
echo "abc123def456 # chore: apply prettier formatting" >> .git-blame-ignore-revs
git config blame.ignoreRevsFile .git-blame-ignore-revs
For ESLint, a gradual approach works better. Start with "warn" severity for new rules, fix violations over time, then switch to "error" once the codebase is clean.
Conclusion
Prettier and ESLint are not competitors — they are complementary tools that solve different problems. Prettier eliminates all formatting debates by enforcing a consistent style automatically. ESLint catches bugs, enforces best practices, and helps you write more reliable code.
The ideal setup for most projects is:
- Install both Prettier and ESLint
- Use
eslint-config-prettierto disable conflicting rules - Configure your editor to format on save (Prettier) and auto-fix on save (ESLint)
- Set up pre-commit hooks with Husky and lint-staged
- Run both checks in CI/CD to catch anything that slips through
This combination gives you a codebase that is both consistently formatted and free of common bugs and anti-patterns. Your code reviews can focus on architecture, logic, and design instead of arguing about semicolons.
Ready to start formatting your code right now? Try our JavaScript Formatter for quick browser-based formatting, or use our JSON Formatter to clean up your configuration files before committing them to your project.
Free Developer Tools
If you found this article helpful, check out DevToolkit — 40+ free browser-based developer tools with no signup required.
Popular tools: JSON Formatter · Regex Tester · JWT Decoder · Base64 Encoder
🛒 Get the DevToolkit Starter Kit on Gumroad — source code, deployment guide, and customization templates.
Top comments (0)