

ESLint - Foundation
- Updated 2025-08-26
The following are my recommendations for ESLint, Prettier, Stylelint, and editorconfig.
ESLint 9
Use the latest version of ESLint 9.
Plugins
These are the plugins with rulesets (with some customization) that will form the foundation of your ESLint setup. Some of these are optional/opinionated and are discussed in following articles.
- AirBnB Extended
- Better Tailwind (if you use Tailwind)
- Canonical
- Check File
- Config Prettier
- Comments
- Import-X
- Import Resolver TypeScript
- Jest DOM
- Jest Formatting
- jsx-a11y
- no-relative-import-paths
- no-switch-statements (optional)
- Prefer Arrow
- Prettier
- React
- React Hooks
- SonarJS
- Storybook
- Testing Library
- TypeScript Enum
- Unicorn
- Unused Imports
- Vitest
- You Don't Need Lodash
Here is my recommended configuration in the eslint.config.mjs
file. You can choose to modify the setting of the rules as you see fit, but I believe these rules should all be set to something.
Details
You can lookup any of the rules yourself and decide if you want to change the setting. Here are my justifications for some of them.
- max-params - In functional programming, you should ideally only have 1 param per function. In practice, this can be a bit too restrictive, so having a limit of 3 params is sensible before converting to a single object with named params. Too many params requires developers to memorize the order and also makes multiple optional params a pain. It does not matter if you can look up the signature or TypeScript helps you. In practice, this limit is better. React components are a great example of this in practice because props is single object param.
- @stylistic/quotes - This ensures optimal quotes for all 3 types (single, double, backtick).
- react/jsx-boolean-value - Being explicit is better, and it makes props look consistent. Even for people who don’t prefer this, since it fixes on save, they can write it without being explicit, and when they save, it makes it explicit, and thus consistent for everyone.
- @typescript-eslint/array-type - Pick the setting you prefer. There are good arguments for both array and generic. This enforces one or the other automatically and consistency is our goal. It automatically fixes to the preferred one on save, so developers can write whichever is more comfortable for them.
- max-lines - If your components are getting too large, it’s usually a sign that you should break them up into smaller ones for performance, readability, and separation of concerns. There are going to be exceptions here and there. In those cases, the developer can disable this rule in the file, and it can be discussed during a code review. In my experience, nearly all of my component files are less than 200 lines, and the rule allows up to 300, by default.
- @typescript-eslint/consistent-type-definitions - You should use
type
for functional programming and immutability.interface
is for OOP and mutability. This article has a good explanation why. No matter what, you want to consistently use one or the other. The rule is disabled for.d.ts
files because third party libraries may requireinterface
.
.prettierrc
These are my Prettier settings.
{
"bracketSpacing": false,
"experimentalTernaries": true,
"plugins": ["prettier-plugin-tailwindcss"], // if you use tailwind
"singleQuote": true,
"tabWidth": 2,
"tailwindFunctions": ["twJoin", "twMerge"], // if you use tailwind
"trailingComma": "es5"
}
bracketSpacing
Some people like bracketSpacing. I think it makes code wider than it needs to be, and I don’t find that it improves readability. If you like it, stick with the default setting.
experimentalTernaries
You can read about them here. These will eventually become the default, so I enable them to get used to them sooner. I agree with the Prettier team that they are better.
plugins
If you use Tailwind, you should use the Tailwind Prettier Plugin.
singleQuote
It is easier to type single quotes (does not require typing two keys at once), and whether it is more common to use apostrophes or double-quotes inside of strings, it does not outweigh how frequently you type single quotes while coding. Single quotes have been the standard for a very long time, and, in my experience, everyone sets this to true
.
tabWidth
Set this to your preference. I used to prefer 4, but I've gotten used to 2, which is more popular these days.
tailwindFunctions
If you use Tailwind, you should use Tailwind Merge, instead of clsx or classnames.
trailingComma
Trailing commas are great! But, I don’t like them in function parameters. I think they look messy before the closing parentheses and arrow const foo = (a, b, c,) =>
. So, I set this to “es5” instead of “all”.
.stylelintrc.json
Here are my suggested settings for Stylelint.
{
"extends": [
"stylelint-config-standard",
"stylelint-config-idiomatic-order",
"stylelint-config-tailwindcss"
],
"ignoreFiles": ["public/build/**/*.css"],
"overrides": [
{
"files": ["**/*.module.css"],
"rules": {
"selector-class-pattern": "^[a-z][a-zA-Z0-9]+$"
}
}
],
"plugins": ["stylelint-order"],
"rules": {
"at-rule-no-deprecated": null,
"no-descending-specificity": null,
"selector-pseudo-class-no-unknown": [
true,
{
"ignorePseudoClasses": ["global", "local"]
}
]
}
}
.editorconfig
IDEs will automatically follow your rules by adding this file to the root of your project. These are my suggested settings.
# editorconfig.org
root = true
# We recommend to keep these unchanged
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
Next article: ESLint - Sorting
Main article: Take your workflow to the next level with ESLint fix on save