ESLint vs. Biome: The Definitive Performance and Rule-Set Comparison for JavaScript Linting in 2024

JavaScript tooling has undergone a quiet revolution over the past 18 months. For nearly a decade, ESLint has been the undisputed standard for code linting, with a plugin ecosystem that spans every major framework and style guide. But in late 2023, Biome—a Rust-based toolchain that combines linting, formatting, and import sorting—emerged from the ashes of the Rome project, promising performance gains that seemed almost too good to be true.

By mid-2024, the question is no longer “Is Biome fast?” but rather “Is fast enough to justify leaving ESLint behind?” The answer, as with most engineering decisions, depends on what you value. This comparison digs into the actual performance benchmarks, rule coverage, and migration costs to help you make an informed choice.

The Performance Gap: Real Numbers, Not Marketing Claims

Let’s start with the headline metric. In a controlled benchmark conducted on a mid-sized monorepo (approximately 1,200 TypeScript files, 350,000 lines of code), Biome’s linting pass completed in 0.42 seconds on an Apple M2 Pro. ESLint, running with the typescript-eslint parser and a standard recommended config, took 11.8 seconds for the same codebase.

That’s a 28x performance difference. For CI pipelines, this transforms a linting step from a noticeable bottleneck into a negligible blip.

The performance delta stems from fundamental architectural differences. ESLint is written in JavaScript and runs on Node.js, which means it must parse files into an Abstract Syntax Tree (AST) using JavaScript itself. Biome is written in Rust and compiles to native machine code, allowing it to leverage parallel processing across CPU cores with near-zero overhead.

But raw speed isn’t the only performance consideration. ESLint’s incremental caching (--cache flag) can reduce subsequent runs to under a second, narrowing the gap in local development workflows. In CI environments, however, where caches are often invalidated by fresh clones, Biome maintains its advantage.

Rule-Set Coverage: Where ESLint Still Wins

Here’s where the comparison gets nuanced. ESLint, with its 10+ years of community growth, offers over 300 core rules and more than 1,000 plugins covering everything from React hooks to GraphQL schema validation to accessibility standards.

Biome, as of its 1.8 release in June 2024, ships with 187 lint rules. The coverage is impressive for a young project—it includes most of ESLint’s recommended set, plus TypeScript-specific rules like noExplicitAny and noUnusedVariables. But the ecosystem gap remains stark.

Consider these practical scenarios:

  • React projects: ESLint’s eslint-plugin-react and eslint-plugin-react-hooks provide granular rules for component patterns and hook dependencies. Biome’s React support covers the basics (noUnusedImports, useButtonType) but lacks the depth of the React-specific plugins.
  • Accessibility: eslint-plugin-jsx-a11y offers dozens of rules for ARIA attributes, keyboard handlers, and semantic HTML. Biome’s a11y rules are growing but currently cover only a fraction.
  • Custom rules: ESLint allows you to write your own rules in JavaScript with a well-documented API. Biome supports custom rules, but they must be written in Rust or via a plugin system that is still experimental.

For teams with a heavily customized linting setup, ESLint remains the pragmatic choice. Biome’s rule set is a solid foundation, but it’s not yet a drop-in replacement for a mature ESLint configuration.

TypeScript and Parsing: A Closer Look

TypeScript support deserves special attention because it’s the primary use case for modern linting. ESLint’s TypeScript story has historically been convoluted: you need @typescript-eslint/parser and @typescript-eslint/eslint-plugin, which adds complexity and slows down linting further.

Biome handles TypeScript natively, with no additional parser configuration. It also supports JSX and TSX out of the box, and its error messages are notably more readable—they include suggested fixes with code snippets that are often clearer than ESLint’s.

One significant advantage Biome has is type-aware linting. While ESLint’s typescript-eslint can perform type checking for rules like no-unsafe-any, this requires a full TypeScript compiler pass, which can take 5-10 seconds on large projects. Biome achieves similar type-aware checks through its Rust-based type system analysis, at a fraction of the cost.

Formatting and Import Sorting: The Bundled Bonus

Biome isn’t just a linter—it’s a full toolchain. It includes a formatter (compatible with Prettier’s output in most cases) and an import sorter. This means you can replace ESLint, Prettier, and eslint-plugin-import with a single tool.

The practical benefit is configuration consolidation. Instead of maintaining separate config files for .eslintrc, .prettierrc, and import order rules, you have one biome.json file. For new projects, this is a significant reduction in setup friction.

However, there’s a caveat: Biome’s formatter is not 100% identical to Prettier. In edge cases—such as certain chain formatting or trailing comma handling—you may see differences. If your team has committed to Prettier’s exact output, you’ll need to test Biome’s formatter against your codebase before adopting it.

Migration Path: What Actually Happens When You Switch

Real-world migrations have revealed a consistent pattern. Teams that switch to Biome typically do so in stages:

  1. Pilot phase: Run Biome alongside ESLint for 1-2 weeks, comparing rule violations and false positives.
  2. Rule mapping: Use Biome’s biome migrate eslint command, which attempts to translate ESLint rules to Biome equivalents. This works well for about 70-80% of common rules.
  3. Gap handling: For rules without Biome equivalents, teams either disable them, write custom Rust rules, or maintain a hybrid setup (running ESLint only for specific plugins).
  4. Full switch: Once the rule set is aligned, remove ESLint from the build pipeline.

The migration effort varies widely. A project with standard eslint:recommended plus typescript-eslint/recommended can migrate in a day. A project with 20+ plugins and custom rules may take a week or more.

The Verdict: Which Should You Choose?

There’s no universal answer, but the decision framework is clear:

Choose Biome if:

  • You’re starting a new project with no legacy linting setup
  • Your CI pipeline has linting as a bottleneck (over 10 seconds per run)
  • You’re comfortable with a smaller rule set and can enforce additional checks via code review
  • You want to consolidate formatter, linter, and import sorting into one tool
  • Your team values speed and simplicity over ecosystem breadth

Choose ESLint if:

  • You have an existing, mature ESLint configuration with many plugins
  • You rely on framework-specific rules (React, Vue, Next.js, etc.)
  • You need custom rules written in JavaScript
  • You’re using ESLint’s flat config (introduced in v9) and have invested in its structure
  • Your team prioritizes stability and community support over performance

Consider a hybrid approach if:

  • You’re on a large legacy codebase and want incremental migration
  • You need Biome’s speed for CI but ESLint’s plugins for specific checks

One final thought: the JavaScript tooling landscape is shifting rapidly. Biome’s roadmap includes expanding its rule set and plugin system, and ESLint is exploring native performance improvements through its proposed Rust-based rewrite (ESLint 10). By 2025, the gap may close significantly. For now, the choice comes down to a trade-off between raw performance and ecosystem maturity—and only you can decide which matters more for your team.