Your Linter Needs to Be as Fast as Your AI
AI tools ship code in seconds. Claude Code, Codex, and Cursor generate complete components while you're still typing the prompt. The bottleneck has shifted — it's not writing code anymore, it's validating it fast enough to keep the loop tight.
That's where ESLint falls apart.
ESLint Was Built for a Different World
ESLint wasn't designed for a workflow where your AI commits 300 lines in one shot. It's a plugin framework, and every layer adds cost:
- A parser (
@typescript-eslint/parser, or Babel, or both) - Plugins that extend configs that extend other configs
- Optional type-checking via
tsconfig.json
That last one is the real killer. Type-aware rules like @typescript-eslint/no-floating-promises require ESLint to resolve your entire TypeScript type graph before running. On a medium-sized project, that's 15–30 seconds per run.
ESLint also runs on Node.js. Not a complaint — that's how it ships to everyone. But interpreted JavaScript is just slower than compiled code for CPU-bound parse work.
The result: most teams quietly disable type-aware rules because CI times balloon. Without them, ESLint catches style issues, not logic bugs. You're running a slow tool for modest returns.
What Biome Does Instead
Biome is a linter and formatter written in Rust, with its own parser, and no dependency on the TypeScript compiler.
| ESLint + Prettier | Biome | |
|---|---|---|
| Runtime | Node.js (JavaScript) | Native (Rust) |
| Parser | External or separate | Built-in |
| Formatter | Prettier parses again | Same AST as linter |
| Type-checking | Optional, expensive | None (syntax-only) |
| Config surface | Plugins + extends chains | Single biome.json |
The double-parse problem alone matters at scale. ESLint parses your files, then Prettier parses them again for formatting. Biome parses once and runs both passes on the same AST.
According to Biome's own benchmarks, formatting runs ~25x faster than Prettier (multithreaded on modern hardware) and linting runs ~15x faster than ESLint on equivalent rule sets. Single-threaded, the numbers drop to around 7x and 4x respectively. Both figures come from Biome's benchmark suite, not independent testing — and the ESLint comparison deliberately excludes type-aware rules because Biome doesn't support them. Run the benchmark on your actual codebase before committing to the numbers.
Everything runs in parallel across files by default.
Setting Up Biome
npm install --save-dev --save-exact @biomejs/biome
npx @biomejs/biome init
init generates a biome.json. A working config for a TypeScript React project:
{
"$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"trailingCommas": "es5"
}
}
}
Add to package.json:
"scripts": {
"lint": "biome lint ./src",
"format": "biome format --write ./src",
"check": "biome check --write ./src"
}
biome check runs lint, format, and import sorting in one pass. That's the command you want on save and in CI.
For VS Code, install the Biome extension and set it as the default formatter:
{
"[javascript]": { "editor.defaultFormatter": "biomejs.biome" },
"[typescript]": { "editor.defaultFormatter": "biomejs.biome" },
"[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome" }
}
Disable Prettier if it's installed — they'll conflict on save.
The Tradeoffs
Biome's rule surface is smaller — around 250 rules vs ESLint's 1,000+. No @typescript-eslint/no-misused-promises. No eslint-plugin-react-hooks. No type-aware rules at all, because Biome doesn't run the TypeScript compiler. Custom rules written in JavaScript aren't possible; Biome's rules are compiled Rust, so you're limited to what the project ships.
Migrating also means a large formatting diff on day one. Biome's formatter matches Prettier's output in most cases, but not all. If your repo has clean formatting history, expect one noisy commit.
These are real limitations. Whether they matter depends on how much you rely on niche rules.
What Changes When AI Writes the First Draft
Here's where the calculus shifts. ESLint's value was always in catching things humans missed — a convention violation, a misused promise, a forgotten dependency in a hook. That assumed humans were writing every line, slowly, and needed a safety net.
With AI generating the first draft, fixing a lint violation costs almost nothing. You paste the error into the chat. The fix comes back in seconds. The cost of a missed rule is no longer "engineer spends ten minutes debugging a subtle bug" — it's "engineer spends five seconds asking the AI to fix it."
That changes what you need from a linter. You need it fast enough to run on every save, tight enough to catch obvious errors, and simple enough that it never becomes the thing you're debugging. Biome fits that. A 200-rule ESLint config with three plugin dependencies that occasionally breaks on a Node.js version mismatch does not.
The conventions ESLint used to enforce by rule, AI now enforces through context. If your AI knows your codebase uses a certain pattern, it follows it. The linter's job shrinks to: does this code parse, are the obvious errors gone, is the formatting consistent.
AI Development Makes Fast Validation Non-Negotiable
Six months ago you wrote 50 lines and linted them. Now you review 300 AI-generated lines and need to validate before the next task. The feedback cycle has compressed.
If npm run lint takes 20 seconds, you skip it. You commit the code, push, and let CI catch it. CI runs later, context is cold, and fixing it costs more attention than the original lint would have.
Biome runs fast enough that skipping it stops making sense. biome check --write across 300 files takes under a second on a modern machine — fast enough to run on every save, which is exactly when you need it.
I switched from ESLint to Biome on my own projects. The speed difference was immediately obvious in the save-on-format loop. What I gave up: a handful of type-aware rules I was barely reading the output of anyway. What I gained: a linter I actually leave on.
The argument for keeping ESLint is flexibility. That argument was stronger when conventions were hard to enforce any other way. Now that AI fixes violations on demand, what you need from a linter is fast, cheap feedback — and Biome already has it.