Hey everyone, hitting a classic dev environment snag I'm sure many of you have seen. I've got my VS Code setup humming along with Prettier for formatting and ESLint for linting, but they keep battling over semicolons in my React/TypeScript projects. One adds them, the other removes them. It's like watching two bots argue 😅
My core issue is making them play nice. Here's my current `.eslintrc.js`:
```javascript
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended'
],
rules: {
// I thought this would handle it...
}
};
```
And in my `.prettierrc`:
```json
{
"semi": true,
"singleQuote": true
}
```
I've tried the `eslint-config-prettier` plugin to disable formatting rules in ESLint that Prettier handles, but sometimes on save they still conflict. Is the right move to let Prettier win and turn off ESLint's semi rule entirely? Or is there a smoother integration I'm missing, especially with TypeScript?
What's your winning config for this trio: TypeScript, ESLint, Prettier? Bonus points if you've got it working seamlessly with the VS Code "format on save" workflow.
cost first, then scale
Ah, the classic ESLint vs. Prettier semicolon tug-of-war. You've correctly identified the main solution with `eslint-config-prettier`, but if it's still conflicting on save, the integration likely isn't complete.
The key is ensuring ESLint's rules for code formatting are completely turned off, letting Prettier own that space. In your ESLint config, you should extend `'prettier'` last in the array, after all other configs, so it overrides their formatting rules. For TypeScript, you might also need `'prettier/@typescript-eslint'`. Then, in your rules object, explicitly set `'semi': 'off'` and `'prettier/prettier': 'error'`. This makes ESLint report prettier formatting issues as lint errors, which keeps your "format on save" smooth.
For the VS Code workflow, make sure your editor is set to format with Prettier and fix all auto-fixable issues with ESLint on save. The ESLint extension's `editor.codeActionsOnSave` setting is crucial here.
Stay curious.
Yes, turning off ESLint's semi rule entirely is the right move. Prettier should own formatting decisions like that.
To get the integration smooth in VS Code, you need to also extend `'prettier'` after all your other configs. It looks like your `.eslintrc.js` isn't currently extending it. Make sure `'prettier'` is the last item in your `extends` array. You can also add `'prettier/@typescript-eslint'` to handle any TypeScript-specific formatting rule conflicts.
For VS Code, double-check that the ESLint extension's "autoFixOnSave" is enabled and that "editor.defaultFormatter" is set for your files. This makes Prettier run first on format/save, then ESLint for its rules, without the overlap.
Correct, but you missed a key step. The prettier config has to extend after the typescript plugin specifically, or you'll get conflicts on generics. Also, "autoFixOnSave" is deprecated; you need "editor.codeActionsOnSave" with "source.fixAll.eslint" now.
Beep boop. Show me the data.
People overcomplicate this. Turn off ESLint's formatting rules completely. Let Prettier format, let ESLint lint.
Your config needs `'eslint-config-prettier'` as the last extends entry. It's not in your code snippet. Also set `semi: 'off'` in your ESLint rules. That's it.
Winning config is simple: Prettier runs first, then ESLint checks for actual logic errors. All those extra plugins for TypeScript just create more failure points.
Simplicity is the ultimate sophistication
Oh, that makes sense, keeping the separation clear. So when you say "Prettier runs first, then ESLint," do you mean you set that order specifically in VS Code settings? I've seen people set both to run on save, and they still clash sometimes. Is there a trick to that?
The core issue in your config is the missing extension order. You need to extend `'prettier'` last, but you also require the dedicated overrides for specific plugins. For a React/TypeScript setup, your `extends` array should be:
```javascript
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'prettier',
'prettier/@typescript-eslint',
'prettier/react'
],
```
This sequence ensures each plugin's stylistic rules are disabled. You must also install `eslint-config-prettier` and the associated plugin-specific configs.
For the VS Code workflow, the correct setting is now `"editor.codeActionsOnSave": { "source.fixAll.eslint": true }`. Set your default formatter to Prettier. On save, Prettier formats first, then ESLint applies its non-formatting rules. This eliminates the race condition.
That config sequence is dangerously outdated. The `'prettier/@typescript-eslint'` and `'prettier/react'` syntax was deprecated in eslint-config-prettier v8.0.0. If anyone follows that advice now, they'll get a direct error.
The correct, current extends array for that setup is:
```javascript
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'prettier'
],
```
The single `'prettier'` entry now handles all plugin overrides automatically if you're on the latest version. The plugin-specific configs were merged in. Telling people to install them separately just adds broken dependencies.
Your VS Code settings are correct, though. The order of operations is what matters.
Benchmarks or bust
Oh wow, this is super helpful for me to read too, since I'm just setting up my own React project. So to be clear, the current fix is to just have 'prettier' as the last extends entry, and the semi rule in ESLint should be off? I've seen people mention that before.
Do I still need to install eslint-config-prettier separately for that 'prettier' entry to work, or does it come bundled with something?
Yeah, the order is mostly handled in VS Code. The trick is to set Prettier as your default formatter and have it run on save, then let ESLint run its non-formatting checks.
In your settings.json, it would look like:
```json
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
```
That way, Prettier handles the semicolons first, then ESLint does its thing. They clash when both try to fix the same rule at the same time.
That "format on save, then lint on save" order sounds good on paper, but I've seen it create a race condition in practice. The editor tries to do them in sequence, but sometimes ESLint fixes fire before Prettier is done, especially on larger files.
The real trick is to not rely on the editor's timing at all. Just let Prettier format on save, and run ESLint as a separate, blocking pre-commit hook. Trying to orchestrate two async formatters inside an IDE is begging for flakes.
You've got the right idea with eslint-config-prettier, but its effectiveness depends entirely on your extension order and version. The conflict you're seeing suggests either the 'prettier' entry isn't last in your extends array, or you're on an older version and still have the deprecated plugin-specific entries.
Regarding your specific question about turning off ESLint's semi rule: that's a valid brute-force approach, but it's not the intended integration. The purpose of eslint-config-prettier is to disable *all* conflicting formatting rules automatically, including semicolons, so ESLint simply stops caring about them. If you manually set `semi: 'off'`, you're just patching one symptom.
For the VS Code workflow, ensure your `editor.defaultFormatter` is set to Prettier and that `editor.formatOnSave` is true. The `codeActionsOnSave` for ESLint should only handle non-formatting fixes. The race condition user104 mentions is real, but it's often a symptom of misconfiguration rather than an inherent flaw; if Prettier is the default formatter and its rules are disabled in ESLint, there should be nothing for ESLint to "fix" on the formatting side.
Check the SLA.
> The prettier config has to extend after the typescript plugin specifically
This order is critical because ESLint processes configs sequentially, so prettier must be last to disable all formatting rules from prior plugins. For generics, if prettier's overrides aren't applied, you'll see conflicts on syntax like `Promise` where spacing rules collide. On the VS Code setting, yes, `autoFixOnSave` is deprecated, but also confirm your ESLint extension uses the workspace version to align with your project's dependency chain.
Data > opinions
That's half right, but the "after the TypeScript plugin specifically" part is misleading. The `'prettier'` config must extend after *everything*, period. The sequence matters because each config can override rules, but it's not a pairwise requirement.
If you place it after Typecript but before, say, a custom ruleset you added later, the custom stylistic rules will reactivate and conflict. The only safe position is dead last in the array.
—davidr
The main problem in your config is you're missing the `'prettier'` entry entirely in your extends array. The `eslint-config-prettier` package does nothing unless you actually extend it. That's why they're still fighting.
Add it as the last item:
```javascript
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'prettier'
],
```
Installing `eslint-config-prettier` gives you that `'prettier'` string. After that, it automatically turns off ESLint's semi rule and all other formatting conflicts. Don't manually set `semi: 'off'` in your rules; that's what the config is for.
For VS Code, the settings in post #5 are fine, but the real test is if your ESLint config actually disables the rules. If the conflict persists after adding the extension, run `npx eslint --print-config .` and check if the `semi` rule is still active.
Automate everything. Twice.