Plate 63
Biome vs ESLint: Should You Switch? 0.41s vs 18.7s
Biome 2.5.15 check vs ESLint 9.39.4 + Prettier 3.8.4 on react-hook-form (317 files): 0.41 s vs 18.7 s sequential stack (ESLint 13.58 s, Prettier check 5.22 s). migrate eslint: 54/476 direct, ~50% covered. Biome 200 errors/427 warnings vs ESLint 0/562; 9 format diffs; 287 noExplicitAny from recommended.
Aditya Challa6 min read
On react-hook-form (317 files), Biome 2.5.15 check took a median 0.41 s. The same tree under ESLint 9.39.4 plus Prettier 3.8.4 took 18.7 s wall clock when I ran them back to back (ESLint alone 13.6 s, Prettier --check 5.2 s).
Short answer: switch if you want one tool for lint plus format and your rules are mostly what Biome already covers. Keep ESLint, or run both, if you lean on Playwright rules, type-only unused checks, or a deliberately relaxed any policy. No affiliate links in this post.
What I tested
- Machine: 8 vCPU Intel Xeon / 15 GB RAM Linux cloud box, Node 20.19.2, tested 5 Oct 2026 (about 22:35 to 22:45 IST). The box is shared, so I interleaved the tools each round.
- Repo: react-hook-form at commit
91856c2(4 Oct 2026), installed from its own lockfile. Flat ESLint config: typescript-eslint 8.61.1recommended, eslint-plugin-react, react-hooks, simple-import-sort, eslint-plugin-prettier, eslint-plugin-playwright.no-explicit-anyis off in that config. - Biome: 2.5.15 with a
biome.jsonthat enables recommended rules plus hooks andnoConsole, and turns a11y recommended off so the run stays closer to the repo's ESLint set. Formatter set to 2-space, single quotes, trailing commas. - Timing: three interleaved runs each; median wall-clock for the whole command. Also one sequential ESLint-then-Prettier pass for the stack total.
- Migration probe:
biome migrate eslinton the repo config (no--writekept for the timed runs). - One surprise: Biome's recommended set raised 287
noExplicitAnyhits. The repo's ESLint config turns that rule off, so a naive "recommended Biome" swap is not a drop-in severity match. - Not tested: Biome type-aware lint, editor extensions, autofix output diffs, Vue/Svelte, Windows/macOS.
Is Biome faster than ESLint plus Prettier?
| Setup | Median | Runs |
|---|---|---|
| ESLint 9.39.4, repo config, single thread | 13.58 s | 13.47 / 15.11 / 13.58 |
ESLint, --concurrency auto | 8.68 s | 8.68 / 10.30 / 8.10 |
Prettier 3.8.4 --check (src, e2e, scripts, root configs) | 5.22 s | 5.39 / 5.22 / 5.12 |
| ESLint then Prettier, sequential wall | 18.74 s | one pass |
Biome check (lint + format + assist) | 0.41 s | 0.41 / 0.40 / 0.42 |
Biome lint only | 0.34 s | 0.34 / 0.33 / 0.36 |
Biome format only | 0.22 s | 0.22 / 0.24 / 0.22 |
Biome checked 317 files. On this box, check was about 33x faster than single-thread ESLint and about 46x faster than the ESLint+Prettier stack. ESLint's own --concurrency auto cut lint to 8.7 s; it still did not close the gap. Formatting alone: Prettier --check 5.2 s vs Biome format 0.22 s (~24x).
For CI cold runs, the stack number is the one that matters. Local re-runs with ESLint --cache would look kinder; I did not re-measure cache here because the oxlint comparison on the same repo already covered that path.
Does Biome catch the same problems?
No. Counts on the same tree:
| Tool | Files | Errors | Warnings | Notes |
|---|---|---|---|---|
| ESLint (repo config) | 301 lintable | 0 | 562 | Mostly @typescript-eslint/no-unused-vars, including "only used as a type" |
Biome check (recommended-ish) | 317 | 200 | 427 | Plus 118 infos; 9 of the errors were format mismatches |
Top Biome categories were not a mirror of ESLint: 287 noExplicitAny, 64 organize-imports assists, 62 useOptionalChain, 47 useless lone blocks, 36 useHookAtTopLevel, and only 30 noUnusedVariables (plus 16 noUnusedImports). ESLint's 562 warnings were dominated by unused-vars in type-test files. Different rule defaults, different findings.
Format: Prettier reported every checked file clean. Biome format flagged 9 files, mostly line-break choices inside long TypeScript generics. That is a real migration cost even when lint is the reason you switched.
biome migrate eslint reported 476 ESLint rules in the expanded config: 54 migrate directly (plus 11 inspired, 16 nursery), about 50% (241) fully covered by Biome, and a long unsupported list that includes Playwright rules, prettier/prettier, and simple-import-sort/*. Keep those as a thin ESLint pass if you still need them. The Biome 2.5.15 release notes post covers what that version added for type inference and nursery rules.
How do I switch without losing checks?
- Run
biome migrate eslint(add--include-inspiredif you want the extra matches) and read the unsupported list before you delete anything. - Diff severity. If your ESLint config turns
no-explicit-anyoff, turn Biome'ssuspicious/noExplicitAnyoff too, or CI will fail on noise this repo never linted. - Move formatting deliberately. Compare
biome format --writeon a branch to Prettier; expect a handful of wrapping diffs even when--checkwas clean under Prettier. The oxfmt vs Prettier Markdown test is a related formatter decision if Markdown is in scope. - Keep ESLint for Playwright and any plugin Biome lists as unknown. Run Biome first in CI, then the thin ESLint set.
- If you only want lint speed and already like Prettier, the oxlint vs ESLint switch post is the closer comparison; Biome's pitch is the combined lint+format binary.
Should you switch from ESLint and Prettier to Biome?
| Situation | My pick |
|---|---|
| New or small TS/React app, standard rules, slow CI lint+format | Biome check as the default |
| Heavy Playwright / custom plugin / import-sort rules | Biome for the covered set, thin ESLint for the rest |
Policy depends on allowing any or type-only unused vars | Tune Biome rules first; do not paste recommended blind |
| You already switched lint to oxlint and only need a faster formatter | Stay on oxlint + Prettier or oxfmt; Biome is optional |
| Vue / Svelte / custom parsers | Keep ESLint for those files for now |
Bottom line: on this repo Biome turned an 18.7 s lint+format stack into a 0.41 s check, but it did not reproduce ESLint's warning set and it disagreed with Prettier on 9 files. Who should not switch yet: teams whose lint signal is mostly type-aware unused checks or Playwright plugins. Everyone else can take the speed if they migrate rules on purpose.
How this was made: I ran every command above on the ShopperCove test box and kept the raw JSON and timing logs; the write-up was drafted with AI help and checked against that output.
Sources
- https://github.com/react-hook-form/react-hook-form
- https://biomejs.dev/blog/biome-v2-5/
- https://biomejs.dev/guides/migrate-eslint-prettier/
- https://biomejs.dev/reference/cli/
- https://eslint.org/docs/latest/use/command-line-interface
- https://prettier.io/docs/cli
- https://www.npmjs.com/package/@biomejs/biome
Related
- https://www.shoppercove.com/blog/biome-2-5-15-type-inference-nursery-rules-october-2026
- https://www.shoppercove.com/blog/oxlint-vs-eslint
- https://www.shoppercove.com/blog/oxfmt-0-72-native-markdown-formatter-prettier-parity-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/oxlint-1-87-react-suggestions-a11y-fixes-october-2026
- https://www.shoppercove.com/blog/vite-plus-1-0-unified-toolchain-october-2026
- https://www.shoppercove.com/blog/pnpm-vs-npm-vs-bun
Lab evidence
What I found running this
Hands-on on ShopperCove box 5 Oct 2026 ~22:35-22:45 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 20.19.2). Repo react-hook-form @ 91856c2 (4 Oct 2026). ESLint 9.39.4 + typescript-eslint 8.61.1 + eslint-plugin-react + react-hooks + simple-import-sort + eslint-plugin-prettier + playwright; Prettier 3.8.4. Biome 2.5.15 with biome.json recommended + hooks/noConsole, a11y recommended off, formatter 2-space single quotes. Wall medians (3 interleaved runs): eslint 13.577s (13.468/15.110/13.577); eslint --concurrency auto 8.676s; prettier --check 5.220s; eslint+prettier sequential wall 18.742s; biome check 0.409s (0.409/0.399/0.423) on 317 files; biome lint 0.337s; biome format 0.221s. Findings: ESLint 0 errors / 562 warnings; Biome check 200 errors / 427 warnings / 118 infos (top: 287 noExplicitAny, 64 organizeImports, 62 useOptionalChain, 47 noUselessLoneBlockStatements, 36 useHookAtTopLevel, 30 noUnusedVariables, 16 noUnusedImports); format mismatches 9 files. migrate eslint: 476 rules found, 54 direct (+11 inspired, +16 nursery), ~50% (241) fully covered; unsupported includes playwright/, prettier/prettier, simple-import-sort/. Gotcha: repo ESLint has no-explicit-any off; Biome recommended fails CI on any. Not tested: type-aware Biome, autofix diffs, Vue/Svelte, Windows/macOS. No affiliate.
Related links
Plate 69
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.
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
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