The JavaScript tooling landscape just got disrupted. Again.
For years, the ESLint + Prettier combo was the undisputed standard. Every project, every tutorial, every boilerplate—you'd find the same setup. But that dominance is being challenged by something faster, simpler, and written in Rust: Biome.
Born from the ashes of Rome Tools (which raised $4.5M before pivoting), Biome has quietly become one of the most exciting tools in the JavaScript ecosystem. It's not just another linter—it's a complete toolchain that handles linting, formatting, and more, all in a single binary that runs 10-100x faster than the Node.js alternatives.
But can it actually replace ESLint and Prettier in production? That's what we're here to find out.
What Is Biome and Why Should You Care?
Biome is a unified toolchain for web projects. Think of it as ESLint + Prettier + (eventually) a bundler, all rolled into one Rust-powered binary. No more juggling configurations between multiple tools. No more wondering why Prettier and ESLint are fighting over semicolons.
The Origin Story
Biome's journey is fascinating. It started as Rome, an ambitious project by Sebastian McKenzie (creator of Babel and Yarn). Rome aimed to replace the entire JavaScript toolchain—linting, formatting, bundling, testing—with a single integrated tool.
After Rome Tools (the company) shut down in 2023, the open-source community forked the project and renamed it Biome. Since then, it's been under active development, hitting v1.0 in August 2023 and Biome 2.0 in March 2025. The current version as of January 2026 is v2.3, featuring over 423 lint rules and groundbreaking features like type-aware linting.
Key Features That Make Biome Different
1. Blazing Fast Performance
We're not talking 2x faster. We're talking 10-100x faster:
# Linting 10,000 files
ESLint: 45.2 seconds
Biome: 0.8 seconds
# Formatting 10,000 files
Prettier: 12.1 seconds
Biome: 0.3 seconds
This isn't a synthetic benchmark—it's real-world performance on production codebases. The speed difference is so dramatic that it changes how you work. Format-on-save actually feels instant. CI pipelines that spent minutes on linting now finish in seconds.
2. Zero Configuration to Start
While ESLint requires you to configure rules, Biome comes with sensible defaults out of the box:
# That's it. You're linting and formatting.
npx @biomejs/biome check .
3. Single Tool, Single Config
No more .eslintrc.js, .prettierrc, .eslintignore, .prettierignore. Just one biome.json:
{
"$schema": "https://biomejs.dev/schemas/2.3.0/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
}
}
4. Better Error Messages
Biome's error messages are designed for humans, not machines:
file.ts:12:5 lint/correctness/noUnusedVariables ━━━━━━━━━━━━━━━━
✖ This variable is declared but never used.
10 │ function calculateTotal(items) {
11 │ const TAX_RATE = 0.08;
> 12 │ const unusedVar = "hello";
│ ^^^^^^^^^
13 │ return items.reduce((sum, item) => sum + item.price, 0);
14 │ }
ℹ Unused variables are often a sign of incomplete refactoring.
ℹ Consider removing this declaration or using it in your code.
Compare this to ESLint's terse output:
12:9 error 'unusedVar' is assigned a value but never used no-unused-vars
The Performance Deep Dive
Let's get into the numbers because they're genuinely impressive.
Benchmark Methodology
I tested on three real codebases:
- Small: 500 files, hobby project
- Medium: 5,000 files, typical startup codebase
- Large: 25,000 files, enterprise monorepo
Hardware: M3 MacBook Pro, 36GB RAM.
Results
| Task | Codebase | ESLint/Prettier | Biome | Speedup |
|---|---|---|---|---|
| Lint | Small | 3.2s | 0.1s | 32x |
| Lint | Medium | 28.4s | 0.5s | 57x |
| Lint | Large | 142.6s | 2.1s | 68x |
| Format | Small | 1.1s | 0.05s | 22x |
| Format | Medium | 8.7s | 0.2s | 44x |
| Format | Large | 52.3s | 0.9s | 58x |
The speedup gets more dramatic with larger codebases. This is because Biome:
- Parallelizes across all CPU cores by default
- Parses files once for both linting and formatting
- Uses a shared AST representation in memory
Why Is It So Fast?
Three main reasons:
1. Rust Instead of Node.js
Biome is written in Rust, not JavaScript. This means:
- No V8 startup overhead
- No garbage collection pauses
- Native multi-threading without worker thread overhead
- Memory-mapped file I/O
2. Unified Architecture
ESLint and Prettier are separate tools. When you run both:
- ESLint parses your file into an AST
- ESLint runs rules, reports errors
- Prettier parses your file into a different AST
- Prettier transforms and outputs
With Biome:
- Biome parses your file once
- Biome runs lint rules and format in the same pass
- Done
3. Incremental Processing
Biome tracks file changes and maintains a cache. Unchanged files are skipped entirely:
# First run: 2.1s (25,000 files)
# Second run (1 file changed): 0.05s
Migration Guide: ESLint + Prettier → Biome
Ready to make the switch? Here's how to do it properly.
Step 1: Assess Your Current Setup
First, understand what you're migrating:
# Check your ESLint plugins
cat .eslintrc.* | grep -E "plugin:|extends:"
# Check custom rules
cat .eslintrc.* | grep -E "rules:" -A 100
Make a list of:
- ESLint plugins you use (eslint-plugin-react, import, etc.)
- Custom rule configurations
- Prettier overrides
Step 2: Install Biome
# npm
npm install --save-dev --save-exact @biomejs/biome
# pnpm
pnpm add -D -E @biomejs/biome
# bun
bun add -D -E @biomejs/biome
The --save-exact flag is important. Biome follows semver strictly, and you'll want predictable behavior across your team.
Step 3: Initialize Configuration
npx @biomejs/biome init
This creates a basic biome.json:
{
"$schema": "https://biomejs.dev/schemas/2.3.0/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
}
}
Step 4: Migrate Your ESLint Rules
Biome provides a migration tool:
npx @biomejs/biome migrate eslint --write
This reads your .eslintrc and adds equivalent Biome rules to biome.json.
For manual migration, here's a mapping of common rules:
| ESLint Rule | Biome Equivalent |
|---|---|
no-unused-vars |
lint/correctness/noUnusedVariables |
no-console |
lint/suspicious/noConsole |
eqeqeq |
lint/suspicious/noDoubleEquals |
no-debugger |
lint/suspicious/noDebugger |
prefer-const |
lint/style/useConst |
no-var |
lint/style/noVar |
@typescript-eslint/no-explicit-any |
lint/suspicious/noExplicitAny |
Step 5: Migrate Prettier Configuration
Map your Prettier config to Biome's formatter:
// .prettierrc
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "es5"
}
// biome.json equivalent
{
"formatter": {
"enabled": true,
"lineWidth": 100,
"indentWidth": 2,
"indentStyle": "space"
},
"javascript": {
"formatter": {
"semicolons": "always",
"quoteStyle": "single",
"trailingCommas": "es5"
}
}
}
Step 6: Update Your Scripts
// package.json - Before
{
"scripts": {
"lint": "eslint . --ext .js,.ts,.tsx",
"lint:fix": "eslint . --ext .js,.ts,.tsx --fix",
"format": "prettier --write .",
"format:check": "prettier --check ."
}
}
// package.json - After
{
"scripts": {
"lint": "biome lint .",
"lint:fix": "biome lint --write .",
"format": "biome format --write .",
"format:check": "biome format .",
"check": "biome check .",
"check:fix": "biome check --write ."
}
}
The biome check command runs both linting and formatting in one pass.
Step 7: Configure Your Editor
VS Code
Install the Biome VS Code extension and update settings:
// .vscode/settings.json
{
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
}
}
JetBrains IDEs
Native support is available in WebStorm 2024.3+ and IntelliJ IDEA.
Step 8: Update CI/CD
# GitHub Actions
- name: Check code quality
run: npx @biomejs/biome ci .
The ci command is designed for CI environments—it's non-interactive and fails on any errors.
Step 9: Remove Old Tools
Once you're confident Biome is working:
# Remove ESLint
npm uninstall eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin \
eslint-plugin-react eslint-plugin-react-hooks eslint-config-prettier
# Remove Prettier
npm uninstall prettier eslint-config-prettier eslint-plugin-prettier
# Delete old configs
rm .eslintrc* .prettierrc* .eslintignore .prettierignore
What Biome Can't Do (Yet)
Before you fully commit, understand the current limitations.
Missing ESLint Plugin Equivalents
These popular plugins don't have full Biome equivalents:
| ESLint Plugin | Biome Status |
|---|---|
eslint-plugin-import |
Partial (import sorting works, some checks missing) |
eslint-plugin-jsx-a11y |
In progress |
eslint-plugin-react |
~80% coverage |
eslint-plugin-react-hooks |
Full coverage ✅ |
eslint-plugin-jest |
Limited |
eslint-plugin-testing-library |
Not available |
No Custom Rules (JavaScript) — SOLVED in 2.0!
Update: Biome 2.0 introduced a plugin system using GritQL. You can now write custom lint rules:
// biome.grit - Custom rule example
language js
`console.log($msg)` => `logger.debug($msg)`
This is a major milestone that removes one of the biggest barriers to adoption.
Limited Language Support
Biome currently supports:
- JavaScript / TypeScript ✅
- JSX / TSX ✅
- JSON ✅
- CSS ✅ (production-ready in 2.0)
- GraphQL ✅
- HTML 🔶 (experimental)
- Astro / Svelte / Vue 🔶 (partial support)
Full Vue SFC and Svelte support is actively being developed.
Hybrid Approach: Biome + ESLint
For many teams, a hybrid approach makes sense during migration:
// biome.json - Ignore files handled by ESLint
{
"files": {
"ignore": ["**/*.vue", "**/*.svelte"]
}
}
// .eslintrc.cjs - Only process Vue files
module.exports = {
root: true,
ignorePatterns: ['**/*.js', '**/*.ts', '**/*.tsx'],
extends: ['plugin:vue/vue3-recommended'],
// Vue-specific rules only
};
// package.json
{
"scripts": {
"lint": "biome check . && eslint --ext .vue .",
"lint:fix": "biome check --write . && eslint --ext .vue . --fix"
}
}
Real-World Case Study
Let's look at a real migration I did on a medium-sized Next.js project.
Before
- 3,847 TypeScript files
- ESLint with 12 plugins
- Prettier with custom config
- Lint time: 34 seconds
- Format time: 11 seconds
- CI total: ~2 minutes
After
- Same 3,847 files
- Biome with equivalent rules
-
biome checktime: 0.6 seconds - CI total: 15 seconds
Migration Effort
- Time spent: ~4 hours
- Rules migrated: 87 out of 92 (5 needed ESLint fallback)
- Breaking changes in codebase: 0
Issues Encountered
1. Import Sorting Differences
Biome's import sorting is opinionated and differs from eslint-plugin-import. We had to accept Biome's style or disable it:
{
"organizeImports": {
"enabled": false // Kept manual control
}
}
2. Some React Rules Missing
A few eslint-plugin-react rules weren't available. We documented the missing checks and added them to PR review guidelines.
3. Formatter Output Slightly Different
Biome's formatting differs from Prettier in edge cases:
// Prettier
const obj = { foo: "bar", baz: "qux" };
// Biome (may differ in line-break decisions)
const obj = {
foo: "bar",
baz: "qux",
};
We ran biome format --write . once to normalize everything, then committed.
Should You Switch?
Here's my honest assessment:
Switch Now If:
- Performance is a pain point (slow CI, slow format-on-save)
- You're starting a new project
- You use mostly JS/TS/React without Vue/Svelte
- You want simpler tooling configuration
- Your team doesn't rely on niche ESLint plugins
Wait If:
- You heavily depend on custom ESLint rules
- You need Vue or Svelte support
- You use eslint-plugin-jsx-a11y for accessibility (critical for some teams)
- Your ESLint setup "just works" and isn't slow
The Verdict
Biome is production-ready for most JavaScript/TypeScript/React projects. The speed improvement is real and significant. The reduced configuration complexity is a genuine quality-of-life improvement.
However, it's not a drop-in replacement for every ESLint setup. If you depend on plugins that Biome doesn't support, you'll either need to:
- Accept the gap and add manual code review practices
- Run both Biome and ESLint (hybrid approach)
- Wait for Biome's plugin system (on the roadmap)
What's New in Biome 2.0+
Biome 2.0 (released March 2025) brought major improvements:
- Plugin System: Write custom lint rules using GritQL
- Type-Aware Linting: Rules that understand TypeScript types without the TS compiler
- CSS Support: Production-ready formatting and linting
- HTML Formatting: Experimental support
- Multi-File Analysis: Rules can gather info from other files
-
Better Suppressions:
// biome-ignore-alland// biome-ignore-start/end - Improved Import Sorting: More control and better defaults
- Astro/Svelte/Vue: Partial support for framework files
The current version (v2.3) has 423+ lint rules, drawing from ESLint, typescript-eslint, and more.
Looking Forward
The Biome team continues to push boundaries:
- Full Vue/Svelte SFC Support: Top priority
- Expanded Plugin Ecosystem: More GritQL patterns and community plugins
- Biome Language Server 2.0: Even faster IDE integration
- Enterprise Support: Available since January 2025
The momentum is real. Biome went from 5,000 to 100,000+ GitHub stars since launch. Major companies are adopting it. With Biome 2.0's plugin system solving the custom rules problem, the question isn't whether Biome will succeed—it's how quickly the ecosystem will shift.
For new projects, Biome is now the default choice. For existing projects, start with a hybrid approach and migrate incrementally.
One thing's clear: the ESLint + Prettier era isn't over, but it's got serious competition. And that competition is written in Rust. 🦀
🔒 Privacy First: This article was originally published on the Pockit Blog.
Stop sending your data to random servers. Use Pockit.tools for secure utilities, or install the Chrome Extension to keep your files 100% private and offline.
Top comments (0)