ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 69

  1. Blog

oxlint vs ESLint: Should You Switch? 9.8s vs 0.09s

oxlint 1.87.0 vs ESLint 9.39.4 on react-hook-form (301 files): 0.09 s vs 9.81 s single-thread (6.02 s with --concurrency auto, 1.10 s warm --cache). @oxlint/migrate ported 42 of 84 rules natively, 80 with JS plugins. 315 vs 562 warnings; seeded test 11/15 native, 13/15 with JS plugins, ESLint 15/15.

Aditya Challa·5 October 2026·7 min read

Summary
On this page
  1. What I tested
  2. Is oxlint faster than ESLint?
  3. Does oxlint catch the same problems?
  4. What does the migration tool leave out?
  5. How do I switch without losing checks?
  6. Should you switch from ESLint to oxlint?
  7. Sources
  8. Related

On react-hook-form's 301 lintable files, ESLint 9.39.4 with the repo's own config took a median 9.8 s, and oxlint 1.87.0 with a migrated config took 0.09 s. The catch: only 42 of the 84 ESLint rules moved over natively, and oxlint reported 315 warnings where ESLint reported 562.

Short answer: switch if your config is mostly core, TypeScript and React rules, and keep ESLint (or run both) if you lean on type-aware rules or plugins oxlint cannot run natively. No affiliate links in this post.

What I tested

  • Machine: 8 vCPU Intel Xeon / 15 GB RAM Linux cloud box, Node 24.21.0, tested 5 Oct 2026 (about 22:25 to 22:35 IST). The box is shared with other jobs, so I interleaved the tools in each round.
  • Repo: react-hook-form at commit 91856c2 (4 Oct 2026), installed from its own lockfile. Its flat config uses typescript-eslint 8.61.1 recommended, eslint-plugin-react, react-hooks, simple-import-sort, eslint-plugin-prettier and eslint-plugin-playwright.
  • ESLint: the repo's pinned 9.39.4, run as eslint . with no cache unless noted.
  • oxlint: 1.87.0. I generated its config with @oxlint/migrate 1.86.0 twice: once native-only (--js-plugins=false) and once with JS plugins, which loads ESLint plugins oxlint lacks.
  • Timing: three runs each, median of wall-clock time for the whole command.
  • Seeded test: one extra .tsx file with 15 planted problems, one for each kind of rule in the config, then deleted.
  • One surprise: the first time I ran oxlint I kept the generated config one folder up. Ignore patterns and overrides resolve relative to the config file, so oxlint linted 311 files and raised 4 no-require-imports errors ESLint never shows. Keeping .oxlintrc.json in the repo root fixed it.
  • Not tested: ESLint 10.12, oxlint's type-aware mode, Vue or Svelte files, editor integration, autofix output.

Is oxlint faster than ESLint?

SetupRulesMedianRuns
ESLint 9.39.4, repo config, single thread849.81 s9.81 / 9.65 / 9.90
ESLint, --concurrency auto846.02 s7.27 / 6.02 / 5.51
ESLint, prettier/prettier turned off835.66 s5.66 / 5.22 / 6.28
ESLint, --cache with nothing changed841.10 s1.10 / 1.22 / 0.92
oxlint, native rules only420.09 s0.31 / 0.09 / 0.09
oxlint, native + simple-import-sort as a JS plugin790.61 s0.69 / 0.60 / 0.61
oxlint, native + all JS plugins (incl. Prettier)804.75 s5.17 / 4.67 / 4.75

Rule counts are as @oxlint/migrate reported them. Native oxlint was about 100x faster than a single-threaded ESLint run. That ratio drops fast once you add JS plugins: running Prettier as a lint rule inside oxlint cost about 4 s, almost the same as running prettier --check 3.8.4 on the same 301 files (4.13 s median). Formatting through the linter is the slow part in both tools.

Two ESLint numbers matter for a fair comparison. Turning on ESLint's built-in multithreading (--concurrency auto) took 9.8 s down to 6.0 s with no other change. And with --cache, an unchanged repo re-linted in 1.1 s, so local re-runs were never the 10 s problem. CI runs without a warm cache are where oxlint pays off.

Does oxlint catch the same problems?

On the real repo, every one of oxlint's 307 unused-variable warnings matched an ESLint warning at the same line and column. Its other 8 warnings (4 react/display-name, 4 Playwright) matched ESLint's per-rule counts. The 247 warnings only ESLint raised were all one pattern in the repo's type-test files: "'actual' is assigned a value but only used as a type." That is a typescript-eslint extension of no-unused-vars, and oxlint's version did not flag it.

The seeded file told the same story:

Planted problemESLintoxlint + JS pluginsoxlint native
Hook called inside ifyesyesyes
useEffect missing a dependencyyesyesyes
console.logyesyesyes
Type used without import typeyesyesyes
Unused variableyesyesyes
Unused type aliasyesyesyes
!!x in a conditionyesyesyes
// @ts-ignoreyesyesyes
varyesyesyes
let never reassignedyesyesyes
Anonymous memo() componentyesyesyes
Unsorted importsyesyesno
Formatting off (Prettier)yesyesno
Value only used as a typeyesnono
Anonymous default-export componentyesnono
Total15 / 1513 / 1511 / 15

The two misses that matter here are both quiet: neither breaks a build, but a team that relies on react/display-name for DevTools names or on the type-only check will lose them without noticing. Check the typescript-eslint 8.71 post if your config uses rules beyond recommended.

What does the migration tool leave out?

@oxlint/migrate read all 84 rules from the flat config. Native-only, it ported 42 and skipped 42: 38 belong to plugins oxlint does not ship (Playwright, Prettier, simple-import-sort), 3 it lists as unsupported (react/jsx-uses-react, react/jsx-uses-vars, react/no-deprecated), and 1 is still a nursery rule (react/require-render-return). With JS plugins on, it ported 80. It also warned that react.version: "detect" and react.pragma settings do not carry over.

JS plugins are still marked alpha in the oxlint docs, and they cannot run type-aware rules yet. If your config uses recommendedTypeChecked, oxlint native alone will not replace it today. The oxlint 1.87 release notes post covers what that version added for React and jsx-a11y.

How do I switch without losing checks?

  1. Run npx @oxlint/migrate eslint.config.mjs --details and read the skipped list before you change anything.
  2. Save the output as .oxlintrc.json in the repo root, not elsewhere, so ignores and overrides resolve the same way.
  3. Move formatting out of the linter. Run Prettier or oxfmt as its own step; the oxfmt vs Prettier test has numbers for that side.
  4. Run oxlint first in CI and keep ESLint for only the rules oxlint skipped. eslint-plugin-oxlint exists for exactly this: it turns off the ESLint rules oxlint already covers.
  5. Diff the warnings from both tools on your main branch once, the way I did above, before you delete the ESLint config.

Should you switch from ESLint to oxlint?

SituationMy pick
Config is mostly core, typescript-eslint recommended, React and hooks rulesoxlint native, with formatting as a separate step
Heavy use of type-aware rulesKeep ESLint, or run oxlint first and ESLint for the type-aware set
Plugins oxlint does not ship (Playwright, import sorting)oxlint with JS plugins, or both tools side by side
Vue, Svelte or Angular templatesKeep ESLint for now; JS plugins do not handle custom parsers yet
ESLint is slow only on your laptopTry --cache and --concurrency auto first

Bottom line: on this repo oxlint went from 9.8 s to 0.09 s and agreed with ESLint on every warning it raised, but it skipped half the rules natively and silently dropped two checks. Who should not switch yet: teams whose lint config is mostly type-aware rules or framework template plugins. Everyone else can get most of the speed by running both and letting oxlint go first.

How this was made: I ran every command above on the ShopperCove test box and kept the raw JSON output; the write-up was drafted with AI help and checked against that output.

Sources

  • https://github.com/react-hook-form/react-hook-form
  • https://oxc.rs/docs/guide/usage/linter.html
  • https://oxc.rs/docs/guide/usage/linter/js-plugins.html
  • https://github.com/oxc-project/oxc/releases
  • https://www.npmjs.com/package/@oxlint/migrate
  • https://eslint.org/docs/latest/use/command-line-interface
  • https://eslint.org/blog/2025/08/multithread-linting/
  • https://typescript-eslint.io/rules/no-unused-vars/

Related

  • https://www.shoppercove.com/blog/oxlint-1-87-react-suggestions-a11y-fixes-october-2026
  • https://www.shoppercove.com/blog/eslint-10-12-release-october-2026
  • https://www.shoppercove.com/blog/typescript-eslint-8-71-no-unsafe-enum-assignment-october-2026
  • https://www.shoppercove.com/blog/oxfmt-0-72-native-markdown-formatter-prettier-parity-october-2026
  • https://www.shoppercove.com/blog/biome-2-5-15-type-inference-nursery-rules-october-2026
  • https://www.shoppercove.com/blog/vite-plus-1-0-unified-toolchain-october-2026
  • https://www.shoppercove.com/blog/vitest-5-should-you-upgrade-october-2026
  • https://www.shoppercove.com/blog/playwright-1-63-test-locks-october-2026
oxlinteslintlintingperformancejavascripttypescriptreactbenchmarking

Lab evidence

What I found running this

Hands-on on ShopperCove box 5 Oct 2026 ~22:25-22:35 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 24.21.0). Repo react-hook-form @ 91856c2 (4 Oct 2026), pnpm install from repo lockfile. ESLint 9.39.4 (repo pin), typescript-eslint 8.61.1, eslint-plugin-react 7.37.5, react-hooks 7.1.1, eslint-plugin-prettier 5.5.6, prettier 3.8.4. oxlint 1.87.0, @oxlint/migrate 1.86.0 (native-only --js-plugins=false: 42 rules, 42 skipped = 38 JS-plugin rules [playwright, prettier, simple-import-sort], 3 unsupported [react/jsx-uses-react, jsx-uses-vars, no-deprecated], 1 nursery [react/require-render-return]; JS-plugins mode: 80 rules, jsPlugins eslint-plugin-prettier + simple-import-sort). Wall time, 3 interleaved runs: eslint . 9.81/9.65/9.90; --concurrency auto 7.27/6.02/5.51; prettier off 5.66/5.22/6.28; --cache warm 1.10/1.22/0.92; oxlint native 0.31/0.09/0.09; oxlint + simple-import-sort JS plugin 0.69/0.60/0.61; oxlint + all JS plugins 5.17/4.67/4.75; prettier --check 300 files 4.14/4.13/4.00. Findings: ESLint 301 files 0 errors 562 warnings (554 no-unused-vars, 4 display-name, 2+2 playwright); oxlint 315 warnings (307 no-unused-vars all matching ESLint line+col, 4 display-name, 4 playwright). 247 ESLint-only = 'assigned a value but only used as a type' in src/typetest. Seeded 15-problem .tsx: ESLint 15/15, oxlint+JS 13/15 (misses only-used-as-type, anonymous default export display-name), native 11/15 (also misses import sort, prettier). Gotcha: config outside repo root -> 311 files + 4 no-require-imports errors (paths resolve relative to config). Seed file deleted; repo unchanged except untracked .oxlintrc-*.json in bench clone. Not tested: ESLint 10.12, oxlint type-aware, Vue/Svelte, editor, autofix. No affiliate.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Related links

  • Plate 78

    oxlint 1.87.0: React suggestion fixes + jsx-a11y hardening (5 Oct 2026)

    oxlint published v1.87.0 on 5 October 2026: suggestion support for three React/unicorn rules and jsx-a11y/label/mouse/lang hardening plus other fixes. npm latest 1.87.0 confirmed; ShopperCove docs checklist only; no affiliate.

    5 Oct 2026

  • Plate 16

    ESLint v10.12.0: SourceCode tokens/comments types + rule fixes (2 Oct 2026)

    ESLint published v10.12.0 on 2 October 2026 as a minor release: documentation and TypeScript types for SourceCode#getText(), getLoc(), and getRange() now accept tokens and comments (matching runtime behavior), plus multiple rule fixes including astral/Unicode letter handling and autofix edge cases. npm latest confirmed 10.12.0; ShopperCove docs checklist only; no affiliate.

    5 Oct 2026

  • Plate 51

    Biome 2.5.15: type-inference speedups, nursery rules, HTML formatter (30 Sep 2026)

    Biome published @biomejs/biome@2.5.15 on 30 September 2026: type-inference and HTML formatter performance, plus nursery rules for React defaults, Svelte runes, logical CSS, and more. ShopperCove upgrade checklist only; no affiliate.

    5 Oct 2026

On this page

  1. What I tested
  2. Is oxlint faster than ESLint?
  3. Does oxlint catch the same problems?
  4. What does the migration tool leave out?
  5. How do I switch without losing checks?
  6. Should you switch from ESLint to oxlint?
  7. Sources
  8. Related
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove