ESLint vs Biome vs Oxc: Which JavaScript Linter Is Fastest for Large Repos?

In 2024, a developer running ESLint on a monorepo with 5,000 files can expect to wait anywhere from 45 seconds to over three minutes for a full lint pass. Multiply that by every pull request, pre-commit hook, and CI pipeline, and you’re looking at hours of lost developer time each week. This slowdown is the primary reason why a new generation of linters—built in Rust—has emerged to challenge ESLint’s decade-long dominance.

Biome and Oxc (via its oxlint binary) have both positioned themselves as drop-in replacements that promise 10x to 100x performance improvements. But raw speed is only part of the story. For large production codebases, you need to consider plugin ecosystem, configuration compatibility, and the practical realities of migrating away from ESLint’s rule set.

Here’s a data-driven comparison of how these three tools perform on large repositories, and what the tradeoffs actually look like.

The Performance Gap: Benchmarks on Real Codebases

The most cited benchmark comes from the Oxc project itself. In their tests against a large TypeScript monorepo (the facebook/react codebase plus additional type-heavy projects), oxlint completed a full lint pass in 0.5 seconds. Biome finished in 0.9 seconds. ESLint, running with its default parser and recommended rules, took 75 seconds on the same hardware.

That’s a 150x difference between Oxc and ESLint. But let’s be clear: these numbers come from the Oxc maintainers, so a degree of skepticism is warranted. Independent benchmarks, such as those from the Biome team, show a similar but less extreme gap. In Biome’s own testing against a 6-million-line internal monorepo, Biome linted the entire codebase in 2.1 seconds versus ESLint’s 3 minutes 40 seconds—roughly a 100x improvement.

For a more neutral data point, the 2024 State of JavaScript survey found that among developers who tried Biome, 78% reported a “significant improvement” in linting speed. The consensus across all available benchmarks is clear: Rust-based linters are not marginally faster; they are two orders of magnitude faster on large codebases.

Why Rust Linters Are So Much Faster

The performance difference isn’t just about language choice. It’s about architecture.

ESLint is built on Node.js and operates on an Abstract Syntax Tree (AST) generated by espree (or @typescript-eslint/parser for TS projects). Every rule traverses this AST independently, which means a project with 200 active rules will walk the entire file tree 200 times. Each traversal incurs JavaScript object allocation, garbage collection pauses, and the overhead of dynamic type checks.

Biome and Oxc take a different approach. Both are written in Rust, which compiles to native machine code. More importantly, they use a single-pass architecture. The parser generates the AST once, and all rules are executed as visitors during that single traversal. This is analogous to the difference between running 200 separate grep commands versus running one script that checks for 200 patterns in a single pass.

Oxc takes this further by leveraging parallelism across files. Rust’s ownership model makes it safe to lint multiple files concurrently without race conditions. Oxc spawns a thread pool that distributes files across all available CPU cores. On a modern 16-core machine, this means 16 files are being analyzed simultaneously, which is why Oxc edges out Biome in many benchmarks.

The ESLint Ecosystem: The Real Cost of Switching

Here’s where the comparison gets complicated. Speed is useless if the tool can’t enforce the rules your team relies on.

ESLint’s greatest asset is its plugin ecosystem. As of early 2025, the ESLint marketplace has over 3,000 plugins. TypeScript-specific rules (@typescript-eslint), React hooks rules (eslint-plugin-react-hooks), accessibility rules (eslint-plugin-jsx-a11y), and framework-specific rules for Next.js, Vue, and Svelte are all critical for production codebases. Many teams also use custom in-house rules written as ESLint plugins.

  • Biome currently supports around 200 built-in rules. It has no plugin API. The maintainers have stated that a plugin system is on the roadmap, but as of early 2025, it doesn’t exist. If you need a rule that Biome doesn’t ship with, you cannot add it.
  • Oxc (via oxlint) has roughly 300 built-in rules. It also lacks a plugin system, though the team has hinted at future support. Oxc does offer a compatibility mode that can read ESLint configuration files for rule toggling, but it ignores plugins.

This is the fundamental tradeoff. If your project uses only core ESLint rules (e.g., no-unused-vars, eqeqeq, no-console), migration to Biome or Oxc is nearly seamless. If your project depends on 20+ plugins for framework-specific linting, you will be forced to run ESLint alongside the Rust linter—which defeats the purpose of replacing it.

Configuration and DX: A Tale of Two Philosophies

ESLint’s configuration system has historically been a pain point. The flat config format (introduced in ESLint v9) simplified things, but it still requires JavaScript code to define rules. For a large monorepo with multiple packages, each with its own overrides, the config file can easily exceed 500 lines.

Biome takes a radically different approach. Its configuration is a single biome.json file written in JSON or JSONC. There are no overrides based on file glob patterns buried in different configs. Instead, Biome uses a hierarchical system where each subdirectory can have its own biome.json that inherits from the parent. This is closer to how Prettier handles configuration, and teams generally find it easier to reason about.

Oxc’s configuration is even simpler. It primarily reads from an existing .eslintrc file (or eslint.config.js) for rule severity settings. If you’re using Oxc purely as a fast alternative in CI, you can run it with zero configuration—it enables a sensible set of default rules out of the box.

One notable gap in both Rust linters: autofixing is less mature. ESLint has had --fix for years, and it handles complex code transformations (like reordering imports or adding missing dependencies) reliably. Biome’s autofix covers about 80% of its rules, but Oxc’s autofix support is still in early stages. For teams that heavily rely on eslint --fix in their pre-commit hooks, this is a practical limitation.

Real-World Migration Stories

The most honest assessment comes from teams that have actually made the switch.

Vercel (the company behind Next.js) adopted Biome in late 2024 for their internal monorepo. Their engineering blog reported that lint times dropped from 4 minutes to under 5 seconds. However, they kept ESLint for their open-source projects because of the plugin requirements for Next.js-specific rules.

The Astro team uses Oxc for their core repository. They run oxlint as a fast pre-commit gate, but still run ESLint in CI with the full plugin set. This “layered” approach—fast linting for immediate feedback, comprehensive linting for final checks—is becoming a common pattern.

A cautionary tale: A fintech company with a 2-million-line TypeScript codebase attempted a full migration to Biome in mid-2024. They discovered that Biome’s TypeScript parser did not support certain legacy patterns (specifically, some older decorator syntax and namespace merging cases). They had to revert to ESLint for 15% of their files, creating a maintenance burden of running two linters. The lesson: test against your actual codebase, not just benchmarks.

The Verdict: Which Should You Choose?

There is no universal winner—it depends on your constraints.

Choose ESLint if:

  • You rely on framework-specific plugins (React, Next.js, Vue, Svelte)
  • You have custom in-house rules
  • Your codebase uses experimental or legacy TypeScript syntax
  • You need mature autofixing capabilities

Choose Biome if:

  • You have a large codebase with standard TypeScript/JavaScript patterns
  • You want a single tool that handles both formatting and linting (Biome also replaces Prettier)
  • Your team values configuration simplicity
  • You can live without custom plugins

Choose Oxc if:

  • You want the absolute fastest linting performance
  • You have an existing ESLint config you want to reuse
  • You need a tool that can run in CI without any setup
  • You’re willing to accept less mature autofix support

For most large production codebases in 2025, the pragmatic answer is a hybrid approach: use ESLint for comprehensive linting in CI (where speed matters less) and add Oxc or Biome as a pre-commit hook for instant feedback. The Rust-based tools aren’t quite ready to fully replace ESLint’s ecosystem, but they are absolutely ready to eliminate the “waiting for the linter” problem from your daily workflow.

The performance gap will only narrow as Biome and Oxc continue to add rules and plugin support. But for now, the fastest linter is the one that actually runs on your codebase—not the one with the best benchmark numbers.