The Nightmare of “Configuration Conflicts” Between ESLint and Prettier
If you’ve ever initialized a React or Next.js project, you’re likely familiar with the process of installing dozens of supporting packages. From eslint and prettier to eslint-config-prettier or eslint-plugin-prettier. Just keeping the code clean and properly formatted can eat up an hour of configuration time.
The problem isn’t just the setup. In a real-world project I worked on with over 100,000 lines of code, the npm run lint command took nearly 2 minutes to complete. Sometimes Prettier would finish formatting only for ESLint to report a conflicting error. It was incredibly frustrating. Tools meant to help ended up becoming bottlenecks that slowed down progress.
Why is the ESLint & Prettier Duo Becoming So Heavy?
Maintaining two separate tools for Linting and Formatting reveals several inherent weaknesses:
- Snail-paced speed: Both run on Node.js. As projects grow, repeated Abstract Syntax Tree (AST) analysis keeps the CPU constantly overloaded.
- Overlapping configurations: You’re forced to use intermediate plugins to stop them from “fighting” each other.
- Dependency burden: Looking at
package.json, libraries just for formatting code can sometimes take up 15-20MB innode_modules.
Current Solutions
The developer community usually suggests three main approaches:
- Living with it: Continue using the old duo and optimize with caching. This is safe but doesn’t solve the root speed issue.
- Using a Rust-based Linter: Notably
oxlint, which is blazingly fast. However, it currently focuses solely on linting and lacks formatting capabilities. - Switching to Biome (formerly Rome): An “all-in-one” toolset written in Rust. It serves as a perfect replacement for both ESLint and Prettier.
Why Biome is the ‘Perfect Match’ Right Now
Real-world tests on a medium-sized outsource project show that Biome is about 25 times faster than Prettier. Instead of waiting dozens of seconds, Biome processes thousands of files in milliseconds. It comes with built-in linting, formatting, and automatic import sorting in a single, compact binary.
Here are the steps I took to clean up my project and switch to Biome.
1. Minimal Installation
Instead of installing 5-6 packages, you now only need a single command:
npm install --save-dev --save-exact @biomejs/biome
Note: Use --save-exact to pin the version. This ensures all team members always have the same code formatting style.
2. Instant Configuration
Just run the following command to create the biome.json file:
npx biome init
Biome’s configuration is very intuitive and easy to read. Here is a sample configuration I typically apply to real-world projects:
{
"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
"organizeImports": { "enabled": true },
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": { "useNamingConvention": "warn" }
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"quoteStyle": "single"
}
}
3. Automatic Migration from ESLint/Prettier
Don’t want to re-type hundreds of old rules? Biome provides an incredibly smart automatic conversion command:
npx biome migrate prettier --write
npx biome migrate eslint --write
The tool will automatically read your .eslintrc or .prettierrc files and map them to equivalent configurations. This process saved me at least 30 minutes of manual review.
4. Enjoying the Execution Speed
To check for errors and reformat all your code, use the command:
# Check for errors, auto-fix, and format
npx biome check --write .
I usually add these commands to the scripts section of package.json to standardize the process for the whole team:
"scripts": {
"lint": "biome check .",
"lint:fix": "biome check --write ."
}
Setting Up a ‘Gatekeeper’ on GitHub Actions
To prevent bad code from reaching the main branch, integrating Biome into your CI is an essential step. Because Biome runs so fast, it adds almost no waiting time to your pipeline.
name: CI
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- name: Run Biome
run: npx @biomejs/biome ci .
The biome ci . command performs a strict check. If the code isn’t formatted or has linter errors, it will fail immediately.
A Few Notes from Real-World Experience
While Biome is powerful, there are a few minor downsides to consider before switching:
- Ecosystem: Biome doesn’t yet have the massive library of plugins that ESLint does. If your project uses highly specialized rules, check the Biome documentation first.
- VS Code Configuration: Install the Biome extension and set it as your Default Formatter. Avoid running it alongside Prettier, as it will cause formatting conflicts on save.
- Adoption Strategy: For legacy projects, don’t switch everything at once. Test it on a few small folders first to evaluate compatibility.
In summary, Biome is a stellar choice if you prioritize speed and simplicity. The smooth, lag-free coding experience when saving files is something ESLint struggles to provide.
