Biome vs ESLint + Prettier in 2026: Is It Finally Time to Switch?

The "Biome is ready" takes have been circulating since 2024. By 2026, Biome 2.x ships with a proper plugin system, expanded TypeScript coverage, and an import organiser that handles barrel files without melting. The question stopped being "is Biome good" about a year ago. The real question — the one most comparison posts skip — is what switching actually costs on a codebase that's been running ESLint + Prettier for three years.

I ran both stacks on a real mid-size React/TypeScript project: roughly 80k lines, 220 components, monorepo with Turborepo. Here's what the numbers look like.

Setup: Biome vs ESLint + Prettier

Biome wins this hands down. Getting started is two commands:

npm install --save-dev @biomejs/biome
npx @biomejs/biome init

That generates a biome.json with sensible defaults. A production-ready config for a React/TypeScript project:

{
  "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
  "organizeImports": { "enabled": true },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "suspicious": { "noExplicitAny": "warn" },
      "correctness": { "noUnusedVariables": "error" }
    }
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingCommas": "all",
      "semicolons": "always"
    }
  },
  "files": {
    "ignore": ["dist/**", "node_modules/**", "*.d.ts"]
  }
}

One file. No plugins to install. Compare that to a modern ESLint 9 flat config for the same project:

// eslint.config.js
import js from '@eslint/js';
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import reactPlugin from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import importPlugin from 'eslint-plugin-import';
import a11y from 'eslint-plugin-jsx-a11y';
import prettier from 'eslint-config-prettier';

export default [
  js.configs.recommended,
  {
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      parser: tsParser,
      parserOptions: { project: './tsconfig.json' },
    },
    plugins: {
      '@typescript-eslint': tsPlugin,
      react: reactPlugin,
      'react-hooks': reactHooks,
      import: importPlugin,
      'jsx-a11y': a11y,
    },
    rules: {
      ...tsPlugin.configs['recommended-type-checked'].rules,
      ...reactPlugin.configs.recommended.rules,
      ...reactHooks.configs.recommended.rules,
      ...a11y.configs.recommended.rules,
      'import/no-cycle': 'error',
      'import/order': ['error', { 'newlines-between': 'always' }],
    },
  },
  prettier,
];

Then add a .prettierrc, a .prettierignore, resolve the peer dependency warnings, and debug the plugin compatibility issues the docs don't mention. The ESLint 9 flat config migration from .eslintrc alone took most teams a full afternoon — the FlatCompat shim for legacy plugins is its own Stack Overflow rabbit hole.

The VS Code Biome extension handles format-on-save once you point it at biome.json — no separate Prettier extension required. JetBrains WebStorm added native Biome support in 2025 and it works well, though the initial setup involves a few more steps than Prettier's out-of-the-box integration.

Speed: The Rust Advantage Is Real

On the test project:

  • ESLint with type-aware rules enabled: 47s cold, ~28s warm
  • Biome: 1.9s cold, 0.8s warm

Disable type-aware TypeScript rules and ESLint drops to ~12s — but then you lose no-floating-promises, no-unsafe-assignment, and the rest of the rules that catch real production bugs. Biome gets close to that coverage without needing the full TypeScript language service spinning up on every run.

For pre-commit hooks and CI pipelines, this matters practically. A 47-second lint step gets skipped or worked around. A 2-second one doesn't.

Rule Coverage in 2026: Good Enough, With Specific Gaps

Biome 2.x covers the common React/TypeScript patterns well: unused variables, no-console, prefer-const, hooks rules, suspicious any, and a solid correctness rule set. The plugin system introduced in 2.0 means community rules are starting to land, but the ecosystem is still a fraction of ESLint's plugin surface.

The gaps that matter on a real production codebase:

  • import/no-cycle: No Biome equivalent exists yet. On a large monorepo this catches circular dependencies that surface as silent runtime failures. For many teams, this single gap is a blocker.
  • Accessibility (jsx-a11y): Biome has basic a11y rules but nowhere near the coverage of eslint-plugin-jsx-a11y. If you're shipping public-facing UI with real accessibility requirements, this is a meaningful gap — one your users will notice before you do.
  • Testing rules: eslint-plugin-testing-library and eslint-plugin-jest have no Biome equivalents yet. You lose guardrails on anti-patterns like async assertions without await or screen.queryBy* misuse.
  • Type-aware depth: Biome's type inference is improving but it doesn't run TypeScript's full language service. @typescript-eslint/no-floating-promises and @typescript-eslint/consistent-type-assertions still catch things Biome misses.

Before migrating, export your current rule list and check each one against the Biome rules reference. Don't assume "recommended": true covers everything your current config enforces. It almost certainly doesn't.

The Migration Cost Nobody Accounts For

Here's what the "just switch to Biome" posts skip. Migrating an existing codebase isn't swapping config files — it's a full rule audit, a mapping exercise to find equivalents, and then a cleanup run to fix everything Biome flags that your previous config wasn't catching.

On the test project, switching to Biome surfaced 340 new warnings on first run: import ordering differences, formatting inconsistencies from how Prettier handled edge cases, and correctness rules the old ESLint config missed. All auto-fixable, but you need to review the diff before merging it. That's a real afternoon, plus PR review overhead on an 80k-line changeset.

The harder problem: rules with no Biome equivalent. If your team relies on import/no-cycle, you're choosing between dropping the rule entirely (bad idea), running partial ESLint alongside Biome (the worst of both worlds), or waiting for the plugin ecosystem to catch up. None of those is a clean story to take to your team.

If you're reassessing your whole frontend toolchain at once — bundler and linting together — the Vite vs Turbopack comparison is worth reading alongside this. Doing both migrations in a single sprint is more efficient than two separate rounds of config archaeology.

Verdict

New project: use Biome. Setup is faster, CI is faster, there's one fewer tool in your chain, and rule coverage is good enough for most React/TypeScript projects. Start here in 2026 and don't look back.

Existing codebase: stay on ESLint + Prettier unless you have a concrete reason to switch. "Biome is faster" isn't enough justification for a migration sprint unless lint times are actively blocking your workflow. If you do switch, audit your rule list first and accept that you'll lose some coverage in the transition period.

The ESLint flat config migration was painful. If your team already went through that, you're not getting enough back from Biome to justify another round — not yet. The plugin ecosystem is moving fast though. The import/no-cycle and testing library gaps are both heavily requested on the Biome repo. Check back in six months.

H