Oxlint vs Biome: Picking an ESLint Replacement

Oxlint vs Biome comes down to scope, not speed. Oxlint is a linter and nothing else, and it hands type-aware rules to the real TypeScript compiler through a Go sidecar. Biome is a linter and a formatter in one binary, with its own inference engine that never loads tsc. Choose on that split.

Both are written in Rust. Both are fast enough that lint time stops being something you think about, and both will read your existing ESLint config and generate their own. As of August 2026 the current releases are oxlint 1.80.0 and Biome 2.5.10.

What actually differs between oxlint and Biome

Rule coverage first. The oxlint docs put the count at more than 865 rules, ported from ESLint core, typescript-eslint, and the plugins most codebases already depend on: React, react-hooks, Jest, Vitest, import, unicorn, jsdoc and jsx-a11y. Biome crossed 500 rules in v2.5 and promoted 73 nursery rules to stable groups in the same release.

Those numbers are less comparable than they look, because they cover different surfaces. Oxlint lints JavaScript, TypeScript and JSX. Biome also parses and lints CSS, GraphQL, JSON and HTML, which is where a chunk of its rule count lives, and it ships cross-language rules like noUnusedClasses that only make sense when one tool sees both your stylesheet and your JSX.

Configuration is the same idea twice with different filenames. Oxlint reads .oxlintrc.json (also .oxlintrc.jsonc, oxlint.config.ts and oxlint.config.mts), and groups rules by category:

{
  "$schema": "./node_modules/oxlint/configuration_schema.json",
  "plugins": ["typescript", "unicorn", "react"],
  "categories": {
    "correctness": "error",
    "suspicious": "warn",
    "pedantic": "off"
  },
  "rules": {
    "no-console": ["warn", { "allow": ["warn", "error"] }]
  },
  "env": { "browser": true, "es6": true }
}

Biome reads biome.json, generated by biome init, and groups rules by severity group with an extra concept on top called domains:

{
  "linter": {
    "domains": {
      "react": "recommended",
      "test": "recommended"
    },
    "rules": {
      "suspicious": {
        "noDebugger": "error"
      }
    }
  }
}

Domains are the better idea of the two. They group rules by technology rather than by how annoying the rule is, and Biome turns them on automatically when it spots the matching dependency in your package.json. Nobody has to remember to enable the React rules on a React app.

Can either one replace typescript-eslint’s type-aware rules?

Mostly, and by two completely different routes.

Oxlint runs the real compiler. Enabling --type-aware on the CLI, or options.typeAware: true in the root config, delegates to a Go binary called tsgolint, which builds TypeScript programs and runs the type-aware rules while oxlint keeps hold of file traversal, ignore logic, config and reporting. It needs TypeScript 7.0 or later, which shipped this year as the Go port of the compiler, plus a separate install:

npm i -D oxlint oxlint-tsgolint
npx oxlint --type-aware

That gets you 59 of typescript-eslint’s 61 type-aware rules, with the same type semantics you get from tsc because it is the same type system. The oxc docs are upfront about the cost: memory use can get high on very large codebases, and performance is still being worked on. If you have already moved a service onto the newer toolchain, this slots in next to the native TypeScript execution in Node without adding another compiler to the tree.

Biome went the other way. It has its own inference engine, sponsored by Vercel, and its 2026 roadmap claims it as the first tool to ship type-aware lint rules with no dependency on tsc at all. Those rules live in the types domain, and switching any of them on wakes the Biome Scanner, which walks the project and builds the module graph. The equivalent project-level scan in Biome’s own docs takes a 2,000-file project from roughly 800ms to around 2s.

The honest caveat is maturity. noFloatingPromises, the rule most teams actually want type information for, is still in the nursery group as of Biome 2.5. Inference that does not run the compiler is an approximation, and approximations of the TypeScript type system have edges.

So: if type-aware rules are load-bearing in your review process, oxlint’s answer is the correct one by construction. If you want two or three of them and would rather not install a compiler to get them, Biome’s is cheaper.

Do you still need Prettier alongside them?

With Biome, no. biome check --write formats, lints and organises imports in one pass, and it is the reason a lot of teams pick it: two dev dependencies and two config files collapse into one of each. Version 2.5 added --watch to lint, format and check, and a --reporter concise for CI logs that nobody reads until something breaks.

With oxlint, yes, for now. Oxlint does not format. The oxc project has a formatter, oxfmt, but it sits at 0.65.0 and has not hit 1.0, so an oxlint setup in August 2026 is realistically oxlint plus Prettier. That is a real cost. Prettier is the slow half of most lint scripts, and keeping it means the fast linter only fixes half the problem.

How do you migrate off ESLint without a big-bang rewrite?

Both projects ship a converter that reads your flat config.

For Biome it is one command, and a second to draw a line under the violations you are not going to fix today:

npx @biomejs/biome migrate eslint --write
npx @biomejs/biome lint --suppress --reason "suppressed during ESLint migration"

For oxlint, @oxlint/migrate generates a .oxlintrc.json from an existing ESLint flat config. The more interesting path is the incremental one, which oxc explicitly recommends for large repos: run both linters, with eslint-plugin-oxlint switching off every ESLint rule that oxlint already covers.

{
  "scripts": {
    "lint": "oxlint --deny-warnings && eslint ."
  }
}

Oxlint runs first and fails fast on the rules it owns; ESLint then handles only what is left, which is usually a handful of custom or plugin rules with no port yet. Keep eslint-plugin-oxlint on the same version as oxlint itself, since the list of overlapping rules moves with every release. Over a few months the ESLint half shrinks until you can delete it.

Biome has no equivalent coexistence story, because the tool it is really replacing is Prettier plus ESLint together. That makes its migration more of a decision and less of a slope.

Which would we pick?

For a product team on a normal-sized app, Biome. One binary, one config, formatter included, domains that configure themselves, and a type-aware story that is good enough for the two or three rules most teams actually enable. The Prettier deletion alone justifies it.

For a large monorepo with a long tail of custom ESLint rules, oxlint, run alongside ESLint through eslint-plugin-oxlint rather than instead of it. You get the speed on the 95% of rules that are standard, you keep the custom ones working, and when the type-aware rules matter you are running the actual compiler rather than an inference engine that approximates it. Add Prettier and accept that you are running two tools until oxfmt ships 1.0.

The case for neither: if your tsconfig.json is not strict yet, fixing that buys more than swapping linters does. Most of what teams hope a linter will catch, TypeScript catches for free, and we usually start there on a TypeScript codebase audit before touching the lint config at all.

Need this built properly?

Whoooop Ltd has spent 15+ years building and maintaining web applications in TypeScript, React, Node.js and serverless — the same ground this post covers.

Get in touch