Skip to main content

OXC vs ESLint vs Biome: JavaScript Linting in 2026

·PkgPulse Team

TL;DR

The linting space is in flux in 2026. ESLint v9 with flat config is the universal default — 50M+ weekly downloads, every framework supports it. Biome is the fastest all-in-one linter+formatter at near-zero config, and a compelling choice for greenfield projects. OXC (oxlint) is the newest entrant — a Rust-based linter that's 50-100x faster than ESLint — but lacks the rule ecosystem. Most teams should use ESLint v9 or Biome; OXC is worth watching but not production-primary yet.

Key Takeaways

  • ESLint v9 introduced flat config (eslint.config.js) — the old .eslintrc format is officially deprecated
  • Biome v1.9+ handles formatting AND linting in one tool (replaces ESLint + Prettier)
  • OXC (oxlint) is 50-100x faster than ESLint but covers ~300 rules vs ESLint's 700+
  • Biome has ~200 lint rules (growing), zero JavaScript, written in Rust
  • TypeScript support: Biome has first-class TS support; OXC has TS parsing; ESLint needs @typescript-eslint
  • Ecosystem: ESLint has 4000+ plugins; Biome is standalone; OXC ecosystem is nascent

ESLint v9: Flat Config Migration

ESLint crossed 50M weekly downloads in 2026. The biggest change in v9 is the flat config system.eslintrc.* is gone, replaced by eslint.config.js:

Old Way (.eslintrc.json — deprecated)

{
  "env": { "browser": true, "es2022": true },
  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module",
    "project": "./tsconfig.json"
  },
  "rules": {
    "no-console": "warn",
    "@typescript-eslint/no-unused-vars": "error"
  }
}

New Way (eslint.config.js — v9 default)

// eslint.config.js
import globals from "globals";
import js from "@eslint/js";
import tseslint from "typescript-eslint";

export default [
  // Built-in recommended rules
  js.configs.recommended,

  // TypeScript support
  ...tseslint.configs.recommended,

  // Global settings
  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node,
      },
      parserOptions: {
        project: "./tsconfig.json",
      },
    },
  },

  // Your custom rules
  {
    rules: {
      "no-console": "warn",
      "@typescript-eslint/no-explicit-any": "error",
      "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
    },
  },

  // Ignores (replaces .eslintignore)
  {
    ignores: ["dist/**", "node_modules/**", "coverage/**", "*.config.js"],
  },
];

ESLint v9 with React

// eslint.config.js
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";

export default tseslint.config(
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
    },
  }
);

ESLint Performance (2026 Benchmarks)

ESLint is JavaScript, not Rust. For large codebases, it's slow:

Codebase sizeESLint v9BiomeOXC
100 files1.2s0.08s0.03s
500 files5.8s0.3s0.1s
2000 files24s1.1s0.4s

ESLint supports --cache to skip unchanged files, but cold runs are slow.


Biome: The All-In-One Alternative

Biome was born from Rome Tools' pivot — it's a Rust-based formatter + linter + import sorter that replaces ESLint + Prettier in a single binary.

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

biome.json

{
  "$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
  "organizeImports": { "enabled": true },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "correctness": {
        "noUndeclaredVariables": "error",
        "useExhaustiveDependencies": "error"
      },
      "suspicious": {
        "noExplicitAny": "warn",
        "noDoubleEquals": "error"
      },
      "style": {
        "useConst": "error",
        "noNonNullAssertion": "warn"
      }
    }
  },
  "javascript": {
    "parser": {
      "unsafeParameterDecoratorsEnabled": false
    },
    "formatter": {
      "quoteStyle": "double",
      "trailingCommas": "es5"
    }
  }
}

Biome CLI

# Lint and format together
biome check --write .

# Just lint (no formatting)
biome lint .

# Just format
biome format --write .

# CI mode (no changes, just error on violations)
biome ci .

Biome's Rule Coverage

Biome v1.9 ships ~200 lint rules across:

  • correctness — logic errors, exhaustive deps, unused variables
  • suspicious — double equals, commented code, console.log
  • style — const vs let, arrow functions, template literals
  • nursery — experimental rules (opt-in)
  • performance — no-barrel-files, no-array-index-key

What Biome doesn't have: Biome has no plugin system. If you need custom rules, Biome can't do it. ESLint's plugin ecosystem (4000+ packages) is irreplaceable for complex projects.

Biome vs Prettier: Compatibility

Biome formats identically to Prettier for ~97% of cases. The remaining 3% are edge cases where Biome made different aesthetic choices. The biome migrate prettier command handles the gap:

npx @biomejs/biome migrate prettier --write
# Reads .prettierrc and applies those settings to biome.json

OXC: Rust-Speed Linting

OXC (JavaScript Oxidation Compiler) is the Rust-based JavaScript/TypeScript toolchain that includes:

  • oxc_parser — the fastest JS/TS parser in the ecosystem
  • oxlint — linter built on oxc_parser (the installable npm package)
  • oxc_transformer — TS/JSX transformer (Babel replacement)
  • rolldown uses oxc_parser internally
npm install oxlint --save-dev
npx oxlint .

OXC Speed

OXC's headline claim is 50-100x faster than ESLint. From their benchmarks:

CommandESLintOXC
Lint TypeScript (cold)24.0s (2000 files)0.4s
Lint React codebase9.2s (800 files)0.18s

This is achieved by being written in Rust and using multithreaded parsing.

OXC Configuration

// .oxlintrc.json
{
  "$schema": "./node_modules/oxlint/configuration_schema.json",
  "rules": {
    "no-unused-vars": "error",
    "no-console": "warn",
    "eqeqeq": "error",
    "prefer-const": "error"
  },
  "plugins": ["react", "typescript"],
  "env": {
    "browser": true,
    "node": true
  },
  "ignorePatterns": ["dist/**", "node_modules/**"]
}

OXC Rule Coverage

OXC supports ~300 rules including ESLint core rules, React hooks rules, and TypeScript rules. The coverage is growing rapidly, but there are gaps:

OXC has:

  • ✅ All ESLint core recommended rules
  • ✅ React hooks rules (react-hooks/rules-of-hooks, react-hooks/exhaustive-deps)
  • ✅ Common TypeScript rules
  • ✅ Import/no-cycle (graph-based, very fast)

OXC doesn't have:

  • @typescript-eslint advanced type-aware rules (requires type checking)
  • ❌ Custom plugin system
  • ❌ Most framework-specific plugins (Svelte, Vue, Astro)
  • eslint-plugin-security, eslint-plugin-sonarjs

OXC as a Speed Layer

A popular pattern is running OXC first (fast, catches obvious issues) and ESLint only for type-aware rules:

// package.json
{
  "scripts": {
    "lint": "oxlint . && eslint --cache . --rule '@typescript-eslint/no-floating-promises: error'",
    "lint:fast": "oxlint .",
    "lint:types": "eslint --no-eslintrc -c eslint.types.config.js ."
  }
}

Framework-Specific Recommendations

Next.js Project

// eslint.config.js — Next.js uses ESLint by default
import nextPlugin from "@next/eslint-plugin-next";

export default [
  ...tseslint.configs.recommended,
  {
    plugins: { "@next/next": nextPlugin },
    rules: {
      ...nextPlugin.configs.recommended.rules,
      ...nextPlugin.configs["core-web-vitals"].rules,
    },
  },
];

Next.js's eslint-config-next has not been ported to Biome. Use ESLint for Next.js projects.

Vite + React (Biome is a great fit)

npm create vite@latest my-app -- --template react-ts
cd my-app
npm install --save-dev @biomejs/biome
npx @biomejs/biome init
# Remove eslint and prettier from devDependencies

Biome replaces ESLint + Prettier perfectly for Vite/React apps without framework-specific lint rules.

Library Development

Use ESLint. Libraries often need:

  • @typescript-eslint type-aware rules
  • eslint-plugin-jest or eslint-plugin-vitest
  • eslint-plugin-jsdoc for API documentation
  • Custom rules for your library's API patterns

Feature Comparison Table

FeatureESLint v9BiomeOXC
Speed⚠️ Slow (JS)✅ Fast (Rust)✅ Fastest (Rust)
Formatting❌ (needs Prettier)✅ Built-in
Import sorting🔌 Plugin needed✅ Built-in
Rule count✅ 700+ core✅ ~200⚠️ ~300
Plugin ecosystem✅ 4000+ plugins❌ None❌ None
Type-aware rules✅ Full TS support⚠️ Limited
Custom rules✅ Full JS API
Vue/Svelte/Astro✅ Via plugins⚠️ Partial
Config complexity⚠️ Moderate✅ Minimal✅ Minimal
Auto-fix
Editor integration✅ Universal✅ VSCode/JetBrains⚠️ Growing
Weekly downloads50M+3M+Growing

Migration Paths

.eslintrc → ESLint v9 Flat Config

# Official migration helper
npx @eslint/migrate-config .eslintrc.json

This generates an eslint.config.js from your old config. Usually requires manual cleanup.

ESLint + Prettier → Biome

npx @biomejs/biome migrate eslint --write
npx @biomejs/biome migrate prettier --write

Two commands convert your existing configs. Then uninstall ESLint and Prettier.


ProjectRecommendationWhy
Next.js appESLint v9 + next pluginNext.js requires ESLint; flat config is clean
Vite + ReactBiomeNo framework-specific rules needed; Biome is faster
Node.js libraryESLint v9Type-aware rules critical for library quality
MonorepoOXC (fast CI) + ESLint (type rules)Best of both worlds
New SvelteKit projectESLint + svelte pluginBiome/OXC don't support Svelte syntax yet
Legacy Webpack projectESLint v9 (migrate to flat config)Stability over speed

Methodology

  • Benchmarked on a 2000-file TypeScript React codebase (MacBook M3 Pro + GitHub Actions ubuntu-latest)
  • Tested ESLint v9.18, Biome v1.9.3, OXC 0.14.x
  • Reviewed OXC roadmap for rule implementation status
  • Tested all flat config migration paths with official migration tools
  • Analyzed npm download trends for eslint, @biomejs/biome, and oxlint packages

See ESLint vs Biome download trends on PkgPulse — updated in real time.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.