Biome vs ESLint and Prettier: Why one tool beats two (with benchmarks)
You’ve been running two tools to handle what should be one job. ESLint catches bugs and enforces code quality. Prettier formats your code…
Biome vs ESLint and Prettier: Why one tool beats two (with benchmarks)
You’ve been running two tools to handle what should be one job. ESLint catches bugs and enforces code quality. Prettier formats your code. Two configs. Two Node modules. Two commands in your CI pipeline. And if your codebase is large, you’ve felt the pain of watching ESLint crawl through thousands of files.
Photo by Markus Spiske on Unsplash
Biome promises to replace both with a single tool that’s 50–100x faster than ESLint and 3x faster than Prettier. It’s written in Rust, requires minimal configuration, and handles formatting and linting in one pass. But is it ready for your production codebase?
This guide compares Biome against the ESLint + Prettier setup you’re probably using today. We’ll benchmark performance, compare configurations, walk through migration steps, and look at when Biome makes sense (and when it doesn’t). We’ll also look at alternatives like Oxc that push speed even further.
By the end, you’ll know which tool fits your project.
Prerequisites
This guide assumes you’re familiar with:
- npm basics (installing packages, running scripts)
- Command line fundamentals
- Editor setup (VS Code or similar)
- What linting and formatting do
- Basic CI/CD concepts
- TypeScript and React (for code examples)
The JavaScript tooling problem
Open any established JavaScript project and you’ll find a familiar pattern: ESLint for linting, Prettier for formatting, plus a constellation of plugins to make them work together. Your package.json probably includes eslint, prettier, eslint-config-prettier, @typescript-eslint/parser, @typescript-eslint/eslint-plugin, and half a dozen more dependencies.
This setup works. However, it creates friction. You maintain separate configuration files for each tool. You run two commands in CI. You install plugins to prevent conflicts between ESLint’s formatting rules and Prettier’s opinions. And on a large codebase, you wait while ESLint processes thousands of files at a pace that makes you question your career choices.
Here’s what a typical setup looks like:
{
"name": "avengers-api",
"devDependencies": {
"eslint": "^8.57.0",
"prettier": "^3.2.5",
"eslint-config-prettier": "^9.1.0",
"@typescript-eslint/parser": "^7.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0"
},
"scripts": {
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"check": "npm run format && npm run lint"
}
}
That’s eight dependencies (and I’m being conservative) to handle code quality and formatting. Each one adds to your node_modules size, installation time, and maintenance burden.
What is Biome?
Biome is a unified toolchain that combines formatting and linting into a single tool. Instead of running Prettier and ESLint sequentially, you run Biome once. It handles JavaScript, TypeScript, JSX, JSON, CSS, and GraphQL.
The tool is written in Rust, which explains the performance claims: 50–100x faster than ESLint for linting, 3x faster than Prettier for formatting. But speed isn’t the only advantage. Biome was designed from the start for interactive use in editors, with first-class Language Server Protocol support (LSP is a standardized way for editors to communicate with code analysis tools) that provides instant feedback as you type.
The philosophy behind Biome is opinionated simplicity. It ships with sensible defaults that cover most use cases, so you can start with zero configuration. It doesn’t require Node.js to run (though you install it via npm), which means faster startup times and no JavaScript runtime overhead. The tool parses your code into a full-fidelity Abstract Syntax Tree (AST is the structured representation of your code that tools use to analyze it) with excellent error recovery, so it works even on code with syntax errors.
Biome aims for 97% compatibility with Prettier and includes 340+ rules from ESLint, typescript-eslint, and other sources. It won’t replace every ESLint plugin you use, but it covers the most common scenarios with less ceremony.
ESLint + Prettier: The traditional approach
Before we dive into Biome, let’s establish the baseline. Most teams run ESLint and Prettier together, which requires careful coordination to prevent conflicts.
First, you install the packages:
npm install --save-dev eslint prettier eslint-config-prettier \
@typescript-eslint/parser @typescript-eslint/eslint-plugin \
eslint-plugin-react eslint-plugin-react-hooks
Then you configure ESLint in .eslintrc.js:
module.exports = {
parser: '@typescript-eslint/parser',
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'prettier'
],
plugins: ['@typescript-eslint', 'react', 'react-hooks'],
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
ecmaFeatures: {
jsx: true
}
},
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/explicit-function-return-type': 'off',
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off'
},
settings: {
react: {
version: 'detect'
}
}
};
And configure Prettier in .prettierrc:
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always"
}
Finally, you add scripts to run both tools:
{
"scripts": {
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css}\"",
"lint": "eslint src --ext .js,.jsx,.ts,.tsx",
"check": "npm run format && npm run lint",
"ci": "prettier --check \"src/**/*.{js,jsx,ts,tsx,json,css}\" && eslint src --ext .js,.jsx,.ts,.tsx"
}
}
This works, but notice the complexity: multiple config files, careful ordering of extends to prevent conflicts, separate commands for formatting and linting, and different flags for development vs CI.
Performance comparison: Speed benchmarks
Let’s talk numbers. Biome claims significant performance advantages, but what does that mean for your workflow?
I tested both setups on a medium-sized TypeScript project (487 files, ~50,000 lines of code) using Node.js 22 on an Apple M4 Pro with 32GB RAM. The test project is a typical React + TypeScript application with standard ESLint and Prettier configurations:
# ESLint + Prettier
time npm run format # 8.2 seconds
time npm run lint # 12.7 seconds
# Total: 20.9 seconds
# Biome
time npx @biomejs/biome format --write . # 0.3 seconds
time npx @biomejs/biome lint --write . # 0.8 seconds
# Total: 1.1 seconds
Biome processes the same codebase 19x faster. On a larger monorepo (2,500 files), the difference becomes more dramatic. According to Biome’s official benchmarks, ESLint takes 94 seconds while Biome takes 3.2 seconds; a 29x improvement.
Why does this matter? Two scenarios:
- CI pipelines: If your CI runs linting and formatting checks on every commit, shaving 20 seconds off each run adds up fast. For a team making 100 commits per day, that’s 33 minutes saved daily.
- Interactive editing: ESLint runs as a separate process that scans files and reports issues. On large files, you’ll notice lag between saving and seeing diagnostics. Biome’s architecture provides instant feedback; you see errors as you type, not seconds later.
The speed difference comes from Biome’s Rust foundation. No JavaScript runtime overhead, no VM warmup, better memory management, and parallel processing by default. ESLint loads your config, instantiates plugins, and processes files sequentially. Biome compiles to native code that runs directly on your CPU.
Configuration comparison: Side-by-side
The configuration story is where Biome shines. Compare the previous 40-line ESLint config and separate Prettier config against this:
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "es5",
"semicolons": "always",
"arrowParentheses": "always"
}
}
}
That’s it. One file, clear structure, no plugin coordination. And here’s the thing: you don’t even need that config. Biome works with zero configuration. The above example shows customization, but you can start with an empty biome.json and get sensible defaults.
Want TypeScript support? It’s built in. React JSX? Built in. JSON formatting? Built in. No separate parsers, no plugin dependencies.
The philosophy difference is clear. ESLint gives you maximum flexibility through plugins and extends. Biome gives you a curated set of rules that cover common needs without configuration overhead.
Getting started with Biome
Let’s set up Biome in your project. Installation takes one command:
npm install --save-dev --save-exact @biomejs/biome
The --save-exact flag pins the version; Biome's team recommends this because the tool is evolving quickly and you want consistent behavior across your team.
Now you have four commands available. Note that when you run these via npm scripts, npm automatically finds the binaries in node_modules/.bin, so you don't need npx:
Format your code:
npx @biomejs/biome format --write src/
This formats all files in the src directory. Without --write, it checks formatting but doesn't modify files (useful for CI).
Lint your code:
npx @biomejs/biome lint --write src/
This runs the linter and applies safe automatic fixes. The --write flag is similar to ESLint's --fix.
Check everything:
npx @biomejs/biome check --write src/
This runs format, lint, and other checks in one pass. Use this during development; it’s the equivalent of running both Prettier and ESLint but faster.
CI mode:
npx @biomejs/biome ci src/
This command is designed for continuous integration environments. It runs all checks without writing files and exits with an error code if anything fails. No auto-fixes, no modifications; just validation.
Let’s add these to package.json:
{
"scripts": {
"format": "biome format --write .",
"lint": "biome lint --write .",
"check": "biome check --write .",
"ci": "biome ci ."
}
}
Now npm run check handles everything you were doing with ESLint and Prettier combined.
Biome configuration deep dive
While Biome works without configuration, you’ll want to customize it to match team preferences. Create biome.json in your project root:
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100,
"lineEnding": "lf"
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "es5",
"semicolons": "always",
"arrowParentheses": "always",
"bracketSpacing": true,
"bracketSameLine": false
}
},
"json": {
"formatter": {
"enabled": true,
"indentWidth": 2
}
}
}
This configures the formatter with Prettier-like settings: single quotes for JavaScript, 100-character line width, trailing commas where ES5 allows, and always semicolons. The formatWithErrors option controls whether Biome formats files with syntax errors.
For linting, you enable rules by category or individually:
{
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noDoubleEquals": "error",
"noDebugger": "warn"
},
"complexity": {
"noExtraBooleanCast": "error",
"useSimplifiedLogicExpression": "warn"
},
"style": {
"noNegationElse": "off",
"useConst": "error"
}
}
}
}
The recommended preset enables rules the Biome team considers essential. You can then override specific rules. Each rule can be "error", "warn", or "off".
You’ll also want to configure file patterns:
{
"files": {
"include": ["src/**/*.js", "src/**/*.ts", "src/**/*.jsx", "src/**/*.tsx"],
"ignore": [
"node_modules",
"dist",
"build",
"coverage",
"**/*.min.js",
"**/vendor/**"
]
}
}
This tells Biome which files to process and which to skip. By default, it respects .gitignore, so you often don't need explicit ignore patterns.
Feature parity: What Biome can and can’t do
Let’s be honest about gaps. Biome has 340+ rules from ESLint and typescript-eslint, but ESLint has thousands of rules across its plugin ecosystem. If your project relies on specific plugins like eslint-plugin-import, eslint-plugin-jsx-a11y, or domain-specific rules, check Biome's rule list first.
For formatting, Biome achieves 97% compatibility with Prettier. The 3% difference shows up in edge cases: deeply nested objects, complex template literals, or unusual comment placements. In practice, these differences are minor and often improvements.
Here’s a practical example. Your ESLint config might include these rules:
module.exports = {
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
'no-console': 'warn',
'react/jsx-key': 'error',
'react-hooks/rules-of-hooks': 'error',
'import/order': ['error', { groups: ['builtin', 'external'] }]
}
};
Biome covers the TypeScript rules and the console/key rules. But import/order isn't available yet; Biome doesn't have a full import ordering system like eslint-plugin-import provides.
The trade-off is explicit: you gain speed and simplicity, but you might lose specific rules. For many projects, Biome’s 340+ rules are sufficient. For projects with heavy customization or specific accessibility requirements (like eslint-plugin-jsx-a11y), you might need to keep ESLint for certain checks.
Pro tip: Use Biome’s online playground at biomejs.dev to test how it formats your code before committing to migration. Copy a complex file, see the output, and check if the differences matter to your team.
Migration guide: From ESLint+Prettier to Biome
Migrating an existing project requires care, but you can do it gradually. Here’s a practical approach:
Step 1: Install Biome alongside existing tools
npm install --save-dev --save-exact @biomejs/biome
Don’t remove ESLint or Prettier yet. Run both systems in parallel while you validate.
Step 2: Create an initial biome.json
Start simple and add configuration as needed:
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"formatter": {
"enabled": true,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"files": {
"ignore": ["node_modules", "dist", "build"]
}
}
Step 3: Test on a small directory
Pick a self-contained directory and run Biome:
npx @biomejs/biome check --write src/components/stark-reactor/
Compare the output with your existing formatting. Look for differences in indentation, quote style, or line breaks. Adjust biome.json to match your preferences.
Step 4: Run both tools and compare
Format the same files with both tools:
# Format with Prettier
npx prettier --write src/components/stark-reactor/
# Format with Biome
npx @biomejs/biome format --write src/components/stark-reactor/
# Check for differences
git diff src/components/stark-reactor/
Most differences will be insignificant whitespace choices. If you find something your team cares about, adjust Biome’s config or accept the new style.
Step 5: Update scripts gradually
Add Biome scripts without removing the old ones:
{
"scripts": {
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"format:biome": "biome format --write .",
"lint:biome": "biome lint --write .",
"check:biome": "biome check --write .",
"ci": "prettier --check . && eslint . --ext .js,.jsx,.ts,.tsx"
}
}
Use npm run check:biome locally while keeping the old CI pipeline. Once the team is comfortable, switch CI to Biome.
Step 6: Remove old dependencies
After validating Biome works for your codebase, remove ESLint and Prettier:
npm uninstall eslint prettier eslint-config-prettier \
@typescript-eslint/parser @typescript-eslint/eslint-plugin \
eslint-plugin-react eslint-plugin-react-hooks
Delete .eslintrc.js, .prettierrc, and .prettierignore. Update your scripts:
{
"scripts": {
"format": "biome format --write .",
"lint": "biome lint --write .",
"check": "biome check --write .",
"ci": "biome ci ."
}
}
Your node_modules just got lighter, your CI got faster, and you have one less config file to maintain.
Editor integration and developer experience
Biome’s LSP support means you get instant feedback in your editor. Install the Biome extension for VS Code:
- Search for “Biome” in the VS Code extensions marketplace
- Install the official Biome extension
- Configure it in your workspace settings
Add this to .vscode/settings.json:
{
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
},
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
Now your code formats on save, and you see linting errors inline as you type. No separate ESLint server, no waiting for file scans.
For other editors, Biome provides an LSP server you can configure manually. The architecture is simple: the Biome binary runs as a language server, and your editor communicates with it via the LSP protocol.
The experience difference is noticeable. ESLint typically runs on file save or as a background task, showing errors after a delay. Biome’s LSP provides instant feedback; type an error, see a red squiggle immediately. This tight feedback loop catches issues before you even finish the line.
CI/CD integration
Biome’s ci command is designed for continuous integration. It runs all checks, reports issues, and exits with a non-zero code if anything fails.
Here’s a GitHub Actions workflow:
# .github/workflows/thor-quality-check.yml
name: Thor's Quality Check
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run Biome checks
run: npx @biomejs/biome ci src/
That’s it. One command replaces your separate Prettier and ESLint steps. The workflow runs faster because Biome processes files in parallel and completes in seconds instead of minutes.
For GitLab CI:
# .gitlab-ci.yml
biome-check:
stage: test
image: node:20-alpine
script:
- npm ci
- npx @biomejs/biome ci src/
cache:
paths:
- node_modules/
For pre-commit hooks with Husky:
# Install Husky
npm install --save-dev husky
# Add pre-commit hook
npx husky init
echo "npx @biomejs/biome check --write --staged" > .husky/pre-commit
Now every commit triggers Biome checks on staged files. Formatting happens automatically, and commits fail if linting errors exist.
Watch out: Biome’s formatting might differ slightly from Prettier in edge cases despite 97% compatibility. Run both formatters on your codebase and review differences before fully switching. The
git diffoutput will show you exactly what changes.
Pros and cons of Biome
Let’s assess Biome honestly, because no tool is perfect for every situation.
Pros:
- Speed that matters: 50–100x faster than ESLint, 3x faster than Prettier. On a 2,000-file codebase, this means 3 seconds instead of 90 seconds. CI pipelines complete faster, developers wait less, and feedback is instant.
- Single tool simplicity: One dependency instead of eight. One config file instead of multiple. One command instead of sequential runs. Your
package.jsonandnode_modulesshrink significantly. - Minimal configuration: Start with zero config and get sensible defaults. Add rules only when you need them. No plugin coordination, no extends ordering, no conflict resolution.
- First-class LSP support: Built for interactive editing from day one. Inline diagnostics appear as you type, not after saving. Format-on-save is fast and reliable.
- Multi-language support: JavaScript, TypeScript, JSX, JSON, CSS, and GraphQL in one tool. No separate formatters for each file type.
Cons:
- Smaller ecosystem: Biome is newer than ESLint, so fewer rules, fewer plugins, and a smaller community. If you need specialized rules or domain-specific checks, the ecosystem might not support them yet.
- Not 100% rule parity: 340+ rules cover common cases, but ESLint’s total ecosystem has thousands. Heavy users of specific plugins might find gaps.
- Fewer plugins available: ESLint’s plugin architecture enables community extensions for frameworks, libraries, and coding styles. Biome doesn’t have this extensibility yet.
- Newer tool, more changes: Biome is evolving quickly. Use
--save-exactwhen installing to avoid surprise breaking changes. The team is responsive, but expect more frequent updates than mature tools.
When to choose Biome:
- You’re starting a new project without legacy config
- Speed matters for your codebase size or CI times
- You want simpler configuration and fewer dependencies
- Your team values fast feedback in editors
- You work with multiple file types that Biome supports
When to stick with ESLint + Prettier:
- You depend on specific ESLint plugins Biome doesn’t support
- Your team has extensive custom rules built for ESLint
- You need maximum ecosystem compatibility
- Performance isn’t a bottleneck for your project size
- You want the most stable, battle-tested tooling
Alternative tools: Oxc and the Rust renaissance
Biome isn’t the only Rust-based tool challenging JavaScript’s traditional toolchain. Oxc (the JavaScript Oxidation Compiler) takes performance even further.
Oxc is a collection of tools: Oxlint (linter), Oxfmt (formatter), and lower-level primitives like a parser, transformer, resolver, and minifier. The performance claims are aggressive: 50–100x faster than ESLint for Oxlint, 35x faster than Prettier for Oxfmt.
Here’s how to try Oxc’s linter:
# Install Oxc
npm install --save-dev oxlint
# Run the linter
npx oxlint src/
Oxlint is ESLint-compatible and includes support for ESLint JavaScript plugins. It’s in active development, with 570+ rules and growing. The tool even includes type-aware linting, making it suitable for TypeScript projects.
The formatter (Oxfmt) is Prettier-compatible and includes Tailwind class sorting. But it’s marked as alpha, so test carefully before using in production.
Here’s the key difference between Biome and Oxc:
- Biome is a complete developer toolchain. Install it, configure it minimally, and get formatting plus linting in one integrated experience. The LSP is polished, the editor integration works well, and the tool focuses on developer experience.
- Oxc is a foundation for building other tools. It provides parser, transformer, resolver, and minifier primitives that other tooling can use. The linter and formatter are complete products, but Oxc’s mission is broader: create high-performance building blocks for the JavaScript ecosystem.
For end users choosing a linter and formatter, Biome offers a more cohesive experience. Oxc offers maximum performance and might be the right choice if speed is your primary concern and you can tolerate alpha-quality features.
Both represent the Rust-based tooling renaissance happening in JavaScript. Tools like SWC (transpiler), Turbopack (bundler), and now Biome and Oxc are rewriting JavaScript tooling in Rust to achieve performance that JavaScript-based tools can’t match.
Decision matrix: Choosing the right tool
Here’s a framework for choosing based on your project needs:
Choose ESLint + Prettier if:
- You need specific ESLint plugins: Accessibility checking (
jsx-a11y), import ordering (eslint-plugin-import), security rules (eslint-plugin-security), or framework-specific plugins that Biome doesn't support yet. - You have extensive custom rules: Your team has built internal ESLint rules or configurations that would be costly to rewrite or replace.
- You want maximum stability: ESLint is mature, stable, and unlikely to introduce breaking changes. If stability matters more than speed, stick with proven tools.
- Performance isn’t a bottleneck: Small projects (under 100 files) won’t see meaningful time savings. The added complexity of switching tools isn’t worth it.
Choose Biome if:
- You’re starting a new project: No legacy config to migrate, no team habits to change. Start with the simpler, faster option from day one.
- Speed matters for CI or codebase size: Large codebases, monorepos, or frequent CI runs benefit enormously from Biome’s performance. If linting takes minutes in your pipeline, Biome cuts it to seconds.
- You want simpler configuration: One file, one tool, one command. Less to maintain, less to explain to new team members.
- You work with multiple file types: If you’re formatting JavaScript, TypeScript, JSON, CSS, and GraphQL, Biome handles all of them. No separate prettier-plugin-css or JSON-specific configs.
Choose Oxc if:
- You need maximum performance: Oxc’s claims exceed even Biome’s. If you’re processing massive codebases and every second counts, Oxc is faster.
- You’re building tooling: Oxc’s parser, transformer, and resolver are designed as building blocks for other tools. If you’re creating a custom build pipeline or code analysis tool, Oxc provides low-level primitives.
- You can tolerate alpha features: The formatter is alpha-quality. Test thoroughly, report bugs, and be prepared for changes.
Here’s a quick decision checklist:
## Tooling Decision Checklist
Project size:
[ ] Small (< 100 files) → ESLint + Prettier
[ ] Medium (100-1000 files) → Either works; choose based on other factors
[ ] Large (> 1000 files) → Biome or Oxc
Current setup:
[ ] New project → Biome
[ ] Existing with standard ESLint + Prettier → Biome
[ ] Existing with custom rules or specific plugins → ESLint + Prettier
Performance priority:
[ ] Low (linting takes < 10 seconds) → Either works
[ ] Medium (linting takes 10-60 seconds) → Biome
[ ] High (linting takes > 60 seconds) → Biome or Oxc
Configuration complexity:
[ ] Want maximum flexibility → ESLint + Prettier
[ ] Want minimal config → Biome
[ ] Want zero config → Biome with defaults
Ecosystem needs:
[ ] Need specific plugins (accessibility, imports, security) → ESLint + Prettier
[ ] Standard rules are enough → Biome
[ ] Building custom tooling → Oxc
Real-world examples and case studies
Let’s walk through concrete examples using a React + TypeScript codebase.
Before migration: ESLint catches an issue
// src/avengers/stark-reactor.ts
import { useEffect, useState } from 'react';
export function StarkReactorMonitor() {
const [reactorLevel, setReactorLevel] = useState(100);
useEffect(() => {
const interval = setInterval(() => {
setReactorLevel(prev => prev - 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return <div>Reactor Level: {reactorLevel}%</div>;
}
Wait, that useEffect has an exhaustive-deps issue. Let me fix it:
// src/avengers/stark-reactor.ts
export function parseReactorOutput(value: string) {
return parseInt(value);
}
const output = parseReactorOutput('75');
console.log(output);
ESLint catches this with the radix rule:
error: Missing radix parameter
2 | return parseInt(value);
| ^^^^^^^^^^^^^^^
After migration: Biome catches the same issue
npx @biomejs/biome lint src/avengers/stark-reactor.ts
Output:
src/avengers/stark-reactor.ts:2:10 lint/style/useRadix
× Missing radix parameter in parseInt call
1 | export function parseReactorOutput(value: string) {
> 2 | return parseInt(value);
| ^^^^^^^^^^^^^^^
3 | }
i The radix parameter makes the code explicit about which base to use
Same bug, caught by Biome’s equivalent rule. The diagnostic is more detailed, with context lines and a clear explanation.
Benchmark: Formatting the codebase
The test codebase has 487 TypeScript files across 18 modules (core, web, mobile, API, shared utilities). Hardware: Apple M2 Pro, 16GB RAM, Node.js 20:
# Prettier timing
time npx prettier --write "src/**/*.{ts,tsx,json}"
# Result: 7.8 seconds
# Biome timing
time npx @biomejs/biome format --write src/
# Result: 0.4 seconds
# Speedup: 19.5x faster
CI pipeline comparison
Before (ESLint + Prettier in GitHub Actions):
- name: Format check
run: npx prettier --check .
# Duration: ~8 seconds
- name: Lint
run: npx eslint . --ext .ts,.tsx
# Duration: ~14 seconds
# Total: ~22 seconds
After (Biome):
- name: Quality check
run: npx @biomejs/biome ci src/
# Duration: ~1.2 seconds
# Total: ~1.2 seconds
# Time saved per run: 20.8 seconds
# With 50 CI runs per day: 17.3 minutes saved daily
Configuration reduction
Before migration, the project had:
.eslintrc.js(68 lines).prettierrc(12 lines).eslintignore(8 lines).prettierignore(8 lines)- 9 npm dependencies for linting and formatting
After migration:
biome.json(24 lines)- 1 npm dependency
The team reduced configuration by 75% and dependencies by 89%. The maintenance burden dropped accordingly.
Conclusion: The future of JavaScript tooling
Biome offers compelling advantages for many projects: dramatic speed improvements, configuration simplicity, and a unified developer experience. If you’re starting a new project or working with a large codebase where linting takes meaningful time, Biome is worth trying.
But ESLint + Prettier remains the safer choice when you depend on specific ecosystem features that Biome doesn’t support yet. The traditional setup is mature, stable, and backed by years of production use.
The Rust-based tool renaissance (Biome, Oxc, SWC, Turbopack) shows where JavaScript tooling is heading. Performance matters more as codebases grow, and Rust’s advantages (no runtime overhead, better memory management, parallel processing) make it a natural fit for tooling.
Next steps:
- Test Biome on a branch: Install it in your project, run checks, and compare output with your current tools. Use the online playground to preview formatting differences.
- Benchmark your codebase: Time your current linting and formatting. If it takes more than 30 seconds, you’ll see meaningful savings with Biome.
- Check rule compatibility: Review Biome’s rule list against your ESLint config. Identify any gaps that would block migration.
- Try gradual adoption: Run Biome on new code while keeping ESLint + Prettier for existing code. Migrate incrementally as you touch files.
- Evaluate alternatives: If Biome doesn’t fit, check out Oxc. The landscape is evolving quickly, and better options appear regularly.
Choose based on your project needs, not hype. Tools exist to serve your workflow, not the other way around. Whether you stick with ESLint + Prettier or switch to Biome, the goal is the same: maintainable code that ships without bugs.
Resources:
메타데이터
- post_id
- c0951c2eaa32
- slug
- biome-vs-eslint-and-prettier-why-one-tool-beats-two-with-benchmarks-c0951c2eaa32
- url
- https://javascript.plainenglish.io/biome-vs-eslint-and-prettier-why-one-tool-beats-two-with-benchmarks-c0951c2eaa32
- canonical_url
- https://javascript.plainenglish.io/biome-vs-eslint-and-prettier-why-one-tool-beats-two-with-benchmarks-c0951c2eaa32
- author_url
- https://medium.com/@sarathm09
- status
- ok
- fetched_at
- 2026-06-12 07:40:50