Why You Need an ESLint Prettier VS Code Setup
If you write JavaScript, you have probably experienced the frustration of inconsistent code formatting across a team or even within your own files. Tabs vs. spaces, trailing commas, semicolons or not: these small differences add up fast and pollute your pull requests with meaningless changes.
The solution is to combine two powerful tools inside Visual Studio Code:
- ESLint handles code-quality concerns: unused variables, unreachable code, potential bugs, and best-practice violations.
- Prettier handles code-formatting concerns: indentation, line length, quote style, bracket spacing, and more.
When configured correctly, these tools complement each other perfectly. When configured incorrectly, they fight each other and drive developers crazy. This guide walks you through the entire ESLint Prettier VS Code setup from scratch, including how to resolve every common conflict between the two.
Prerequisites
Before you begin, make sure you have the following installed on your machine:
- Node.js (v18 or later recommended)
- npm or yarn
- Visual Studio Code (latest stable version)
This tutorial targets plain JavaScript and Node.js projects. If you use TypeScript, the same steps apply with minor additions noted along the way.
Step 1: Install the VS Code Extensions
Open VS Code and install these two extensions from the Extensions Marketplace:
- ESLint by Dirk Baeumer (
dbaeumer.vscode-eslint) - Prettier – Code formatter by Prettier (
esbenp.prettier-vscode)
You can also install them from the command line:
code --install-extension dbaeumer.vscode-eslint
code --install-extension esbenp.prettier-vscode
Both extensions are required. The ESLint extension highlights linting errors in real time, and the Prettier extension formats your code on demand or on save.
Step 2: Initialize Your Project and Install Dependencies
Navigate to your project folder and make sure you have a package.json. If you do not have one yet:
npm init -y
Now install ESLint, Prettier, and the two packages that make them work together without conflicts:
npm install --save-dev eslint prettier eslint-config-prettier eslint-plugin-prettier
What Each Package Does
| Package | Purpose |
|---|---|
eslint |
The core linter for identifying and reporting code-quality problems. |
prettier |
The opinionated code formatter. |
eslint-config-prettier |
Turns off all ESLint rules that conflict with Prettier so the two tools do not fight. |
eslint-plugin-prettier |
Runs Prettier as an ESLint rule and reports formatting differences as ESLint issues. |
Step 3: Configure ESLint
ESLint now uses a flat config format by default (eslint.config.js). Create a file called eslint.config.js in the root of your project:
import js from "@eslint/js";
import prettier from "eslint-plugin-prettier/recommended";
export default [
js.configs.recommended,
prettier,
{
rules: {
"no-unused-vars": "warn",
"no-console": "warn",
"prefer-const": "error",
"no-var": "error",
"eqeqeq": ["error", "always"]
}
}
];
Note: The eslint-plugin-prettier/recommended preset automatically includes eslint-config-prettier, so you do not need to add it separately. This single import disables conflicting formatting rules and enables the Prettier plugin.
If You Prefer the Legacy .eslintrc Format
Some existing projects still use the older configuration style. Here is the equivalent .eslintrc.json:
{
"env": {
"browser": true,
"es2024": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:prettier/recommended"
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"no-unused-vars": "warn",
"no-console": "warn",
"prefer-const": "error",
"no-var": "error",
"eqeqeq": ["error", "always"]
}
}
Step 4: Configure Prettier
Create a .prettierrc file in the project root to define your formatting preferences:
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"useTabs": false,
"trailingComma": "all",
"printWidth": 80,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf"
}
Recommended Prettier Options Explained
| Option | Value | What It Does |
|---|---|---|
semi |
true | Adds semicolons at the end of statements. |
singleQuote |
true | Uses single quotes instead of double quotes. |
tabWidth |
2 | Sets the number of spaces per indentation level. |
trailingComma |
all | Adds trailing commas wherever valid in ES5+. |
printWidth |
80 | Wraps lines that exceed 80 characters. |
endOfLine |
lf | Enforces Unix-style line endings to avoid cross-OS issues. |
You can also create a .prettierignore file to exclude directories like node_modules, dist, or build from formatting.
Step 5: Configure VS Code Settings
This is where the magic happens. You need to tell VS Code to use ESLint for linting and Prettier for formatting, and to run both automatically when you save a file.
Create or update the file .vscode/settings.json in your project root:
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
]
}
What These Settings Do
- editor.defaultFormatter: Tells VS Code to use Prettier as the default formatter for all files.
- editor.formatOnSave: Automatically formats the file every time you press Ctrl+S (or Cmd+S on Mac).
- editor.codeActionsOnSave: Runs
eslint --fixon save, which auto-fixes linting errors (and, thanks to the plugin, formatting errors too). - eslint.validate: Specifies which languages ESLint should check.
Step 6: Add npm Scripts
Adding scripts to your package.json lets you lint and format from the terminal or in CI/CD pipelines:
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"format:check": "prettier --check ."
}
Now you can run:
npm run lintto check for code-quality issues.npm run lint:fixto auto-fix as many issues as possible.npm run formatto reformat every file in the project.npm run format:checkto verify formatting without changing files (useful in CI).
How to Resolve Common Conflicts Between ESLint and Prettier
The number one complaint developers have with this setup is conflicting rules. ESLint reports an error, you fix it, and then Prettier reformats the code in a way that triggers the ESLint error again. Here is how to solve every common scenario.
Conflict 1: Formatting Rules Clashing
Symptom: ESLint complains about indentation, quotes, or semicolons even though Prettier is handling formatting.
Fix: Make sure eslint-config-prettier is the last item in your extends array (legacy config) or the last element in your flat config array. It must override all previous formatting rules.
Conflict 2: Double Formatting on Save
Symptom: The file flickers or changes twice when you save.
Fix: You are probably running both Prettier (via the extension) and Prettier (via ESLint plugin) at the same time. Choose one approach:
- Option A (recommended): Use Prettier as the default formatter with
formatOnSave, and use ESLint only for code-quality rules (removeeslint-plugin-prettierand just keepeslint-config-prettier). - Option B: Use
eslint-plugin-prettierto run Prettier through ESLint, and disableeditor.formatOnSave. Rely solely oncodeActionsOnSavewithsource.fixAll.eslint.
Conflict 3: endOfLine Errors on Windows
Symptom: Prettier reports “Delete CR” errors on every line.
Fix: Set "endOfLine": "auto" in your .prettierrc if your team works across Windows and macOS/Linux, or configure Git to handle line endings with git config --global core.autocrlf input.
Conflict 4: Rules Not Being Applied
Symptom: ESLint seems to ignore your config file entirely.
Fix: Check which config format you are using. ESLint v9+ uses flat config (eslint.config.js) by default. If your file is named .eslintrc.json, you may need to add "eslint.useFlatConfig": false in your VS Code settings or migrate to the new format.
Complete File Structure Overview
After following every step, your project root should contain these configuration files:
your-project/
├── .vscode/
│ └── settings.json
├── node_modules/
├── eslint.config.js (or .eslintrc.json)
├── .prettierrc
├── .prettierignore
├── package.json
└── package-lock.json
Bonus: Adding TypeScript Support
If your project uses TypeScript, install the additional parser and plugin:
npm install --save-dev typescript-eslint @typescript-eslint/parser
Then update your eslint.config.js:
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import prettier from "eslint-plugin-prettier/recommended";
export default [
js.configs.recommended,
...tseslint.configs.recommended,
prettier,
{
rules: {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "warn"
}
}
];
The VS Code settings from Step 5 already include TypeScript validation, so no changes are needed there.
Testing Your Setup
Create a test file called test.js with intentionally messy code:
var x=1
if(x ==1){
console.log( "hello world" )
}
Save the file. If everything is configured correctly, you should see:
- Prettier reformats the spacing, adds semicolons, and switches to single quotes.
- ESLint highlights
var(because ofno-var), the loose equality (because ofeqeqeq), andconsole.log(because ofno-console). - Auto-fixable issues like
vartoconstget fixed on save.
Quick Reference Cheat Sheet
| Task | How to Do It |
|---|---|
| Install VS Code extensions | dbaeumer.vscode-eslint + esbenp.prettier-vscode |
| Install npm packages | npm i -D eslint prettier eslint-config-prettier eslint-plugin-prettier |
| Prevent rule conflicts | Place eslint-config-prettier last in your config |
| Format on save | Set editor.formatOnSave: true in VS Code settings |
| ESLint auto-fix on save | Set source.fixAll.eslint: "explicit" in codeActionsOnSave |
| Run linting in CI | npm run lint and npm run format:check |
Frequently Asked Questions
How do I set up ESLint and Prettier in VS Code?
Install the ESLint and Prettier extensions in VS Code, add the npm packages (eslint, prettier, eslint-config-prettier, eslint-plugin-prettier) to your project, create configuration files for both tools, and update your .vscode/settings.json to enable format on save and ESLint auto-fix on save. The full walkthrough is covered in Steps 1 through 5 above.
Does Prettier work with ESLint?
Yes. Prettier handles code formatting (indentation, line length, quotes) while ESLint handles code quality (unused variables, bad patterns). The eslint-config-prettier package disables any ESLint rules that would conflict with Prettier so the two tools work side by side without issues.
How do I configure ESLint in VS Code?
Install the dbaeumer.vscode-eslint extension. Then create an eslint.config.js (flat config) or .eslintrc.json (legacy config) file in your project root with your desired rules. The extension automatically picks up the config and displays linting errors inline in the editor.
How do I configure Prettier in VS Code?
Install the esbenp.prettier-vscode extension. Create a .prettierrc file in your project root with your formatting options. Then set "editor.defaultFormatter": "esbenp.prettier-vscode" and "editor.formatOnSave": true in your VS Code settings.
Can I use ESLint and Prettier with TypeScript?
Absolutely. Install typescript-eslint and @typescript-eslint/parser, extend the TypeScript ESLint recommended config in your eslint.config.js, and make sure your VS Code eslint.validate setting includes "typescript" and "typescriptreact".
Why does my code change twice when I save?
This happens when both Prettier (via the formatter extension) and ESLint (via the Prettier plugin) try to format the file. Choose one approach: either use Prettier as the formatter and ESLint only for code quality, or run Prettier entirely through ESLint and disable formatOnSave. See the “Conflict 2” section above for details.
How do I run ESLint in the VS Code terminal?
Add scripts to your package.json as shown in Step 6. Then run npm run lint to check for errors or npm run lint:fix to auto-fix them. You can also run npx eslint . directly in the integrated terminal.
