Data note
26

Data note · Published Apr 22, 2026 · Updated Sep 3, 2026

Your Linter Needs to Be as Fast as Your AI

Biome keeps my AI coding loop moving, but it doesn't replace TypeScript. Here is the current setup and the trade-off I kept.

A field-guide drawing of a camping match tin
In this article6 sections

I switched my own projects from ESLint to Biome because the linter had become the slow part of the loop. Claude Code or Codex could hand me a complete patch, then ESLint made me wait to find out whether the patch was usable.

Biome made the save-and-check cycle feel immediate. I kept TypeScript as a separate check.

Looking back The first version of this post said Biome had about 250 rules, no React Hooks equivalent, and no type-aware rules. That was already stale by Biome 2.5. The project now has more than 500 rules, covers the two core React Hooks rules, and ships its own opt-in type inference. The reason I use Biome hasn’t changed. The limits have.

Where ESLint slowed me down

The ESLint setups I replaced had several moving parts:

  • A parser (@typescript-eslint/parser, or Babel, or both)
  • Plugins that extend configs that extend other configs
  • Optional type-checking via tsconfig.json

Type-aware rules were the expensive part. A rule such as @typescript-eslint/no-floating-promises asks ESLint to load TypeScript’s view of the project before it can report anything useful.

ESLint runs on Node.js while Biome ships a native binary. Runtime alone doesn’t decide the result; the parser, plugins, rules, and files matter too. In these projects, the Biome command was the one that stopped making me wait.

I didn’t need every save to pay that cost. I needed quick syntax and correctness feedback while an agent was changing files, then a full type check before the patch was done.

What Biome changes

Biome is a linter and formatter written in Rust, with its own parser, and no dependency on the TypeScript compiler.

ESLint + PrettierBiome
RuntimeNode.js (JavaScript)Native (Rust)
ParserExternal or separateBuilt-in
FormatterSeparate Prettier processBuilt into the same toolchain
Type analysisTypeScript compiler through typescript-eslintBiome’s opt-in inference for selected rules
Config surfacePlugins + extends chainsSingle biome.json

The simpler path matters more to me than the architecture diagram. One binary owns the parser, formatter, linter, and import assists. An agent gets one short diagnostic stream instead of output from several tools.

I wouldn’t borrow a headline benchmark and call the decision settled. The useful number is the one from the repository you maintain. On September 3, 2026, six warm runs of biome lint . on this site’s checkout had a median wall time of 147 milliseconds in its development container. That isn’t an ESLint comparison. It only confirms that the command is cheap enough to leave in my loop.

Biome 2.5 also changed the rule-catalog argument. It crossed 500 lint rules, including more stable type-aware rules and a concise reporter intended for coding-agent output.

The setup I use

pnpm add --save-dev --save-exact @biomejs/biome
pnpm exec biome init

init generates a biome.json. A working config for a TypeScript React project:

{
  "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "preset": "recommended"
    }
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingCommas": "all"
    }
  }
}

Add to package.json:

"scripts": {
  "lint": "biome lint .",
  "format": "biome format --write .",
  "check": "biome check .",
  "check:fix": "biome check --write .",
  "typecheck": "tsc --noEmit"
}

biome check reads the files and reports problems. The --write version changes them, so I keep that as a separate script instead of letting CI quietly rewrite its workspace.

For an agent patch, the loop is concrete:

pnpm exec biome check --write --reporter=concise src/changed-file.ts
pnpm run typecheck

The first command handles formatting, safe lint fixes, and assists on the changed file. The second lets TypeScript check the complete program. Fast feedback first, deeper feedback before I accept the patch.

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 for the same files or the two formatters will keep disagreeing on save.

What I gave up

Biome still doesn’t reproduce the full ESLint plugin ecosystem. Its React Hooks mappings cover rules-of-hooks and exhaustive-deps, but that doesn’t mean every React plugin rule or option has an equivalent.

Type-aware linting is also narrower than a TypeScript compiler pass. Biome 2 added a scanner and its own inference engine for selected rules; enabling those rules scans the project and costs more than the default single-file path. The project’s original noFloatingPromises test found about 75% of the cases caught by typescript-eslint, and Biome described that figure as preliminary. I still run tsc --noEmit.

Custom rules exist now through GritQL plugins, including code fixes in 2.5. They aren’t drop-in JavaScript ESLint plugins. If a repository depends on a specialized plugin, I check that rule list before removing ESLint.

Migrating can also mean a large formatting diff on day one. Biome aims to stay close to Prettier, but its defaults and some output differ. If your repo has clean formatting history, expect one noisy commit.

These are real limitations. A fast replacement is only useful if it keeps the checks that have caught your actual bugs.

The linter has a smaller job now

ESLint’s value was always in catching things humans missed: a convention violation, a misused promise, a forgotten dependency in a hook.

With AI generating the first draft, I can hand a lint error back to the agent that wrote the code. Quick feedback matters because it arrives while the patch is still small enough to inspect.

That changes what I need from a linter. It has to run on every save, catch obvious errors, and stay out of the way. Biome fits that job better in my projects than a large ESLint plugin stack.

Why I kept Biome

I would keep ESLint in a repository where a plugin catches bugs the team actually sees. My own projects were paying the startup and configuration cost without getting that value back.

Biome finishes quickly enough that I don’t bargain with myself about skipping it. TypeScript still gets the last word.

One quick signal

Did this earn your time?

What was missing?

Thanks. That gives me something concrete to check.