Prettier 01 ๐จ Why Prettier โ An opinionated formatter, not a linter
Prettier is a code formatter. It takes your source code, parses it into an abstract syntax tree, and reprints the entire program from scratch according to a fixed set of formatting decisions. It does not check for unused variables, missing await keywords, or inconsistent naming. It does not know whether your code is correct. It only knows how your code should look. This distinction matters because the JavaScript ecosystem spent years conflating formatting with linting, and the result was slow tools, conflicting rules, and code review comments about semicolons instead of logic.
This chapter explains why Prettier exists as a separate category of tool, why its opinionated nature is a feature rather than a limitation, and how it differs from linters in both architecture and purpose. It covers the two categories of lint rules, the problem with using a linter for formatting, and the specific benefits Prettier provides that no rule-based linter can replicate. By the end, you will understand why the correct answer to “should I use Prettier or ESLint for formatting?” is “both, for different things.”
Key point: Prettier is not a linter with formatting rules turned on. It is a printer that discards your original formatting and emits a consistent representation of the AST. Linters analyze code for bugs; Prettier rewrites it for consistency. They are not competing tools.
Why Prettier exists
The style debate problem. Every development team eventually confronts the question of how code should look: tabs or spaces, semicolons or no semicolons, single or double quotes, trailing commas or none. These debates are emotionally charged and produce no value. Prettier’s creators observed that the biggest reason to adopt Prettier is to stop these debates entirely . By removing the option to configure individual formatting rules, Prettier eliminates the discussion. There is no “Prettier style” to argue about because Prettier is the style.
The linter-as-formatter problem. Historically, linters like ESLint included formatting rules: max-len, keyword-spacing, comma-style, and dozens of others. Running these rules through ESLint was slow because ESLint must parse, check each rule in isolation, report violations, and then run a fix cycle. The TypeScript-ESLint team explicitly recommends against using ESLint for formatting, noting that lint rule fixers can conflict with each other and that formatting through a linter is “much less consistent and less able to handle edge-cases than a purpose-built formatter” . Prettier was built to do one thing and do it comprehensively.
The consistency problem across entire codebases. A linter with formatting rules can only flag code that violates a configured rule. It cannot reformat a file it has never seen, and it cannot normalize edge cases that no rule anticipated. Prettier parses the AST and reprints it, which means every file it touches comes out looking as if the same person wrote it, regardless of who actually did . This is why running Prettier on an inherited or legacy codebase produces immediate uniformity without manual effort.
The mental overhead problem. Formatting code is not programming. It is the mechanical work of breaking lines, aligning brackets, and deciding where to put a comma. Prettier’s documentation quotes users who describe formatting as “5% that sucks in our daily life” and express the desire to “write code, not spend cycles on formatting” . Editor integration means the formatting happens on save, invisibly, and the developer never thinks about it again.
a. The two categories of lint rules
Linters like ESLint contain two fundamentally different kinds of rules, and Prettier only replaces one of them.
The first category is formatting rules. These are rules about whitespace, line breaks, quotes, semicolons, and indentation. Examples include max-len, no-mixed-spaces-and-tabs, keyword-spacing, and comma-style. Prettier eliminates the need for this entire category because it reprints the program from scratch, making it impossible for the programmer to produce inconsistent formatting . There is no rule to configure because there is no decision to make.
The second category is logical rules. These are rules that catch actual bugs: no-unused-vars, no-undef, eqeqeq, no-floating-promises. Prettier does nothing for these rules. It does not analyze your code for correctness, and it will happily format buggy code into a beautiful representation of a bug . The Prettier documentation is explicit about this: “use Prettier for formatting and linters for catching bugs” .
// Prettier formats this, but does not warn you about the bug
const result = fetchData(); // missing await in an async function
// Prettier will make this line look correct:
// consistent spacing, quotes, and semicolons.
// It will not tell you that `result` is a Promise, not data.
The implication for tooling is that Prettier and ESLint are complementary, not alternatives. A project needs both. ESLint catches the bugs; Prettier makes the code readable.
b. How Prettier differs architecturally
The architectural difference between Prettier and a linter is why one is fast and consistent while the other is slow and rule-dependent.
A linter processes code by parsing it, then running each enabled rule against the AST or the token stream. Each rule operates independently. A rule that fixes indentation might produce code that violates another rule’s fixer, forcing ESLint to run additional cycles . The linter must also handle the original formatting as part of its analysis, which means its output depends on what the input looked like.
Prettier’s architecture is different. It parses the code, discards the original formatting entirely, and generates a new representation using an algorithm based on Philip Wadler’s “A prettier printer” . The printer measures the intermediate representation, decides where line breaks should go based on the configured printWidth, and emits a string. The output depends only on the AST and the print width. It does not depend on how the input was formatted.
This is why Prettier is “opinionated.” It has no individual formatting rules to enable or disable. It has a small set of options (printWidth, tabWidth, semi, singleQuote, trailingComma, and a few others) that adjust the output at a high level, but the decisions about where to break lines, how to align arguments, and where to place operators are made by the printer algorithm, not by configurable rules .
c. What “opinionated” actually means
The word “opinionated” in Prettier’s tagline is often misunderstood as a limitation. It is better understood as a scope decision.
Prettier’s Option Philosophy states that Prettier is not a “kitchen-sink code formatter that attempts to print your code in any way you wish” . This is deliberate. Every option that Prettier adds is a decision that teams can argue about, a configuration that can diverge between projects, and a source of inconsistency. The fewer options, the more consistent the output across the ecosystem. The Prettier team has chosen to prioritize consistency over customization.
The practical consequence is that you will sometimes disagree with Prettier’s output. You may prefer a different line break, a different quote style, or a different bracket position. The Prettier documentation addresses this directly: “Even if Prettier does not format all code 100% the way you’d like, it’s worth the ‘sacrifice’ given the unique benefits of Prettier” . The trade is simple: you give up control over minor formatting decisions, and in return you never think about formatting again.
// Prettier will format this object across multiple lines
// if it exceeds printWidth. You cannot configure it
// to keep it on one line if it fits but break if it doesn't.
const config = {
semi: false,
singleQuote: true,
trailingComma: "all",
};
// This is Prettier's decision, not yours.
// That is the point.
Complete Example Session
// ============================================
// PART 1: FORMATTING VERSUS LOGIC
// ============================================
// A formatting issue: inconsistent spacing
const x=1;// Prettier will normalize this
// A logic issue: comparing with == instead of ===
if (x == "1") { /* ... */ } // Prettier will NOT change this
// ESLint with eqeqeq will flag it.
// ============================================
// PART 2: PRETTIER REWRITES THE AST
// ============================================
// Input (intentionally messy):
const user={name:"Alice",age:30,roles:["admin","user"]};
// Output after Prettier:
const user = { name: "Alice", age: 30, roles: ["admin", "user"] };
// The original formatting is gone. The AST is the same.
// ============================================
// PART 3: PRINT WIDTH IS A GUIDELINE, NOT A RULE
// ============================================
// This line may exceed printWidth because it cannot be broken:
const veryLongVariableNameThatCannotBeBrokenWithoutChangingSemantics = "value";
// Prettier will not break string literals or variable names.
// printWidth is a target, not a hard limit.
// ============================================
// PART 4: LINTER CATCHES WHAT PRETTIER CANNOT
// ============================================
async function getData() {
const response = fetch("/api/data"); // missing await
return response.json();
}
// Prettier: formats this correctly.
// ESLint (no-floating-promises): flags the missing await.
// ============================================
// PART 5: CONFIGURING PRETTIER MINIMALLY
// ============================================
// .prettierrc
{
"semi": false,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "all"
}
// These are style preferences, not rule toggles.
// You cannot enable "no-extra-parens" or "comma-dangle".
// ============================================
// PART 6: DISABLING CONFLICTING ESLINT RULES
// ============================================
// .eslintrc.js
module.exports = {
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier", // eslint-config-prettier
],
};
// "prettier" at the end disables all ESLint formatting rules
// that would conflict with Prettier.
// ============================================
// PART 7: PRETTIER IS NOT FORMATTING ON SAVE
// ============================================
// Editor integration is separate from the CLI.
// VS Code settings.json:
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
// The CLI and editor use the same .prettierrc.
// ============================================
// PART 8: CHECKING FORMATTING IN CI
// ============================================
// npm script:
// "format:check": "prettier --check ."
// In CI, this fails if any file is not formatted.
// This prevents unformatted code from merging.
// ============================================
// PART 9: WHAT PRETTIER DOES NOT DO
// ============================================
// Prettier does not:
// - Rename variables
// - Remove unused imports
// - Sort imports (without a plugin)
// - Detect bugs
// - Enforce naming conventions
// - Change code behavior
// These are linter responsibilities.
// ============================================
// PART 10: THE CORRECT MENTAL MODEL
// ============================================
// Prettier: input AST + printWidth -> consistent output
// ESLint: input AST + rules -> bug reports
//
// Run Prettier first (formatting).
// Run ESLint second (analysis).
// Never run ESLint --fix for formatting.
The ten parts covered the formatting-versus-logic distinction, AST reprinting, print width behavior, linter responsibilities, minimal configuration, ESLint integration, editor setup, CI checking, tool boundaries, and the correct execution order.
Quick Reference
Prettier vs. linter responsibilities
| Concern | Prettier | ESLint |
|---|---|---|
| Whitespace and indentation | Yes | No (disable) |
| Quote style | Yes | No (disable) |
| Semicolons | Yes | No (disable) |
| Line breaks | Yes | No (disable) |
| Unused variables | No | Yes |
Missing await | No | Yes |
| Naming conventions | No | Yes |
| Bug detection | No | Yes |
Prettier’s options
| Option | Typical value | Effect |
|---|---|---|
printWidth | 80โ100 | Target line length (guideline) |
tabWidth | 2 | Indentation size |
semi | true / false | Semicolons at statement ends |
singleQuote | true / false | Quote style |
trailingComma | "all" / "es5" / "none" | Trailing commas |
arrowParens | "always" / "avoid" | Parentheses around single arrow arg |
Integration packages
| Package | Purpose |
|---|---|
prettier | The formatter itself |
eslint-config-prettier | Disables ESLint formatting rules |
eslint-plugin-prettier | Runs Prettier as an ESLint rule (slower, not recommended) |
When to run
| Context | Command |
|---|---|
| Local format | prettier --write . |
| CI check | prettier --check . |
| Pre-commit | prettier --write on staged files |
| Editor save | Format on save extension |
Best Practices
โ Do This:
// Use Prettier for formatting only
prettier --write . // โ
// Disable ESLint formatting rules with eslint-config-prettier
extends: ["eslint:recommended", "prettier"] // โ
// Run Prettier before ESLint in CI scripts
"lint": "prettier --check . && eslint ." // โ
// Keep Prettier configuration minimal
{ "semi": false, "singleQuote": true } // โ
// Format on save in the editor for immediate feedback
"editor.formatOnSave": true // โ
โ Don’t Do This:
// Use ESLint formatting rules alongside Prettier
extends: ["eslint:recommended", "prettier", "some-style-config"] // โ
// Run prettier inside eslint-plugin-prettier for performance
plugins: ["prettier"] // โ (slow)
// Expect Prettier to catch bugs
prettier --check . // โ (formatting only)
// Configure every Prettier option to match personal preference
// The point is to stop debating style // โ
// Use Prettier on a codebase that has no ESLint setup
// You will have formatted bugs // โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| ESLint and Prettier conflict | ESLint formatting rules still enabled | Add eslint-config-prettier last in extends |
| Prettier reformats code differently than expected | printWidth is a guideline, not a hard limit | Accept the output; adjust printWidth only if necessary |
| CI fails on formatting | prettier --check finds unformatted files | Run prettier --write . locally before committing |
| Prettier does not catch a bug | It is a formatter, not a linter | Use ESLint with logical rules |
| Slow lint pipeline | eslint-plugin-prettier runs Prettier inside ESLint | Run Prettier separately and use eslint-config-prettier |
Real-World Examples
1. Format a single file
prettier --write src/index.js
2. Check formatting in CI
prettier --check .
3. Minimal Prettier config
{ "semi": false, "singleQuote": true, "printWidth": 100 }
4. Disable ESLint formatting rules
extends: ["eslint:recommended", "prettier"]
5. Format on save in VS Code
{ "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true }
6. Pre-commit hook with lint-staged
{ "lint-staged": { "*.{js,ts}": "prettier --write" } }
7. Run Prettier before ESLint
prettier --write . && eslint --fix .
8. Ignore build output
# .prettierignore
dist/
node_modules/
9. Format only changed files
prettier --write $(git diff --name-only --diff-filter=ACMR | grep -E '\.(js|ts)$')
10. Verify a file’s formatting
prettier --check src/app.js
Visual
Formatter vs. linter pipeline
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SOURCE CODE โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โผ โผ โผ โ
โ PRETTIER ESLINT TYPECHECK โ
โ (formatting) (bug detection) (types) โ
โ โ โ โ โ
โ โผ โผ โผ โ
โ Reprints AST Reports logical Reports โ
โ consistently errors and style type errors โ
โ โ โ โ โ
โ โผ โผ โผ โ
โ FORMATTED CODE BUG REPORTS TYPE ERRORS โ
โ โ
โ These tools do not compete. They cover different concerns. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
What Prettier does to the AST
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PRETTIER TRANSFORMATION โ
โ โ
โ Input: const x={a:1,b:2} โ
โ โ โ
โ โผ โ
โ Parse to AST: โ
โ VariableDeclaration โ
โ โโ VariableDeclarator (x) โ
โ โโ ObjectExpression โ
โ โโ Property (a: 1) โ
โ โโ Property (b: 2) โ
โ โ โ
โ โผ โ
โ Reprint from AST with printWidth and options: โ
โ const x = { a: 1, b: 2 }; โ
โ โ
โ Original formatting (spacing, line breaks) is discarded. โ
โ Only the AST structure survives. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The opinionated trade-off
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ THE OPINIONATED TRADE โ
โ โ
โ You give up: โ
โ - Control over individual formatting decisions โ
โ - The ability to configure every rule โ
โ - The option to format a specific construct differently โ
โ โ
โ You get: โ
โ - Zero style debates โ
โ - Consistent output across the entire team โ
โ - No mental overhead for formatting โ
โ - Fast, predictable formatting โ
โ โ
โ The trade is deliberate. The sacrifice is the feature. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Correct tool ordering
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PIPELINE ORDER โ
โ โ
โ 1. PRETTIER --write โ
โ Normalizes all formatting โ
โ โ โ
โ โผ โ
โ 2. ESLINT --fix โ
โ Fixes logical issues and stylistic non-formatting โ
โ โ โ
โ โผ โ
โ 3. ESLINT (check) โ
โ Reports remaining issues โ
โ โ โ
โ โผ โ
โ 4. COMMIT โ
โ โ
โ Prettier first, because its output must be stable โ
โ before ESLint analyzes it. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Prettier category | Code formatter |
| Linter category | Static analysis / bug detection |
| Prettier’s approach | Reprint AST from scratch |
| Linter’s approach | Rule-by-rule analysis |
| Formatting rules in ESLint | Should be disabled with eslint-config-prettier |
| Logical rules in ESLint | Should be enabled and maintained |
printWidth | Guideline, not hard limit |
| Options count | Small (approximately 15) |
| Configuration philosophy | Opinionated; fewer options for consistency |
| Recommended integration | Separate Prettier and ESLint, run Prettier first |
Key takeaways:
- Prettier is a formatter, not a linter. It reprints the entire program from the AST and discards original formatting. It does not detect bugs, unused variables, or logical errors.
- Linters have two rule categories, and Prettier replaces only one. Formatting rules (
max-len,keyword-spacing) are obsolete with Prettier. Logical rules (no-unused-vars,eqeqeq) remain essential. - “Opinionated” is a scope decision, not a limitation. Prettier removes formatting configuration options to eliminate style debates and guarantee consistency.
- The architectural difference explains the speed and consistency. Prettier measures the AST and emits output based on
printWidth; linters run rules in isolation, which is slower and prone to fixer conflicts. - The correct integration is separation. Use
eslint-config-prettierto disable ESLint’s formatting rules, run Prettier for formatting, and let ESLint handle logic and bugs. - Prettier will format buggy code. It does not care about correctness. A missing
awaitbecomes a beautifully formatted missingawaitafter Prettier runs.
Remember: Prettier exists because formatting is not a decision worth making repeatedly. By removing the ability to configure individual formatting rules, it removes the debates, the inconsistencies, and the mental overhead. The trade-off is real: you will sometimes disagree with its output. But the alternativeโevery developer formatting code according to their own preferences, with a linter slowly flagging violations after the factโis worse. Use Prettier for formatting, use a linter for logic, and keep the two concerns separate. That separation is the entire point.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!