DEV Community

HK Lee
HK Lee

Posted on • Originally published at pockit.tools

Biome: The ESLint and Prettier Killer? Complete Migration Guide for 2026

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
Enter fullscreen mode Exit fullscreen mode

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 .
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

Compare this to ESLint's terse output:

12:9  error  'unusedVar' is assigned a value but never used  no-unused-vars
Enter fullscreen mode Exit fullscreen mode

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:

  1. Parallelizes across all CPU cores by default
  2. Parses files once for both linting and formatting
  3. 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:

  1. ESLint parses your file into an AST
  2. ESLint runs rules, reports errors
  3. Prettier parses your file into a different AST
  4. Prettier transforms and outputs

With Biome:

  1. Biome parses your file once
  2. Biome runs lint rules and format in the same pass
  3. 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Migrate Your ESLint Rules

Biome provides a migration tool:

npx @biomejs/biome migrate eslint --write
Enter fullscreen mode Exit fullscreen mode

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"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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 ."
  }
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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 .
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)`
Enter fullscreen mode Exit fullscreen mode

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"]
  }
}
Enter fullscreen mode Exit fullscreen mode
// .eslintrc.cjs - Only process Vue files
module.exports = {
  root: true,
  ignorePatterns: ['**/*.js', '**/*.ts', '**/*.tsx'],
  extends: ['plugin:vue/vue3-recommended'],
  // Vue-specific rules only
};
Enter fullscreen mode Exit fullscreen mode
// package.json
{
  "scripts": {
    "lint": "biome check . && eslint --ext .vue .",
    "lint:fix": "biome check --write . && eslint --ext .vue . --fix"
  }
}
Enter fullscreen mode Exit fullscreen mode

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 check time: 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
  }
}
Enter fullscreen mode Exit fullscreen mode

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",
};
Enter fullscreen mode Exit fullscreen mode

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:

  1. Accept the gap and add manual code review practices
  2. Run both Biome and ESLint (hybrid approach)
  3. 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-all and // 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)