Gerson

Gerson

Passionate developer specializing in web development, cloud architecture, and system design.

TypeScriptReactNext.jsPythonFastAPISQLNode.jsAWS

Replacing ESLint + Prettier with Biome

Biome collapses ESLint and Prettier into a single Rust tool that runs 25x faster. A full migration walkthrough — config, rule mapping, pre-commit hooks, and the rough edges worth knowing.

Gersonhttps://biomejs.dev/
Code editor showing formatted TypeScript code

Most TypeScript projects still carry ESLint, Prettier, and a pile of plugins that overlap and occasionally fight each other. Biome replaces both with a single Rust binary. Same code gets linted and formatted; the wall-clock cost drops from seconds to milliseconds. My monorepo's pre-commit went from 18 seconds to under one.

This is a migration walkthrough from a real project that had the usual ESLint + Prettier + a dozen plugins setup, plus notes on the rough edges I hit.

What Biome Actually Is

Biome is a single tool that does:

  • Formatting — Prettier-compatible output for JavaScript, TypeScript, JSX, JSON, CSS
  • Linting — ~300 rules covering correctness, style, accessibility, and common TypeScript pitfalls
  • Import sorting — without the eslint-plugin-import config gymnastics

It is written in Rust, it is parallelized, and it parses each file once for lint and format. Benchmarks against eslint . --fix && prettier --write . show 20–30x speedups on medium codebases.

Install and Init

Terminal

pnpm add -D --save-exact @biomejs/biome
pnpm biome init

The init creates biome.json. For most projects, the default is a reasonable starting point.

biome.json

{
  "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
  "files": { "ignoreUnknown": true },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "style": {
        "noNonNullAssertion": "off"
      },
      "correctness": {
        "noUnusedVariables": "error"
      }
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingCommas": "all",
      "semicolons": "always"
    }
  }
}

Removing ESLint + Prettier

Mechanically, the cleanup is short. Delete the config files and uninstall the packages. The list usually looks something like:

Terminal

rm .eslintrc.* .prettierrc.* .prettierignore .eslintignore

pnpm remove \
  eslint \
  prettier \
  eslint-config-prettier \
  eslint-plugin-import \
  eslint-plugin-react \
  eslint-plugin-react-hooks \
  eslint-plugin-jsx-a11y \
  @typescript-eslint/parser \
  @typescript-eslint/eslint-plugin

Update your package.json scripts:

package.json

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

The Rough Edges

A few things to know before you commit:

1. Not every ESLint rule has a Biome equivalent yet

The rule catalog is large but not 1:1. Rules from niche plugins (some framework-specific ones, some security plugins) may not exist in Biome. Before migrating, run biome migrate eslint — it parses your ESLint config and tells you which rules have direct equivalents and which do not.

2. Type-aware linting is limited

ESLint with @typescript-eslint can run rules that require TypeScript's type checker. Biome's type-aware rules are growing but are not yet a complete replacement. If you depend on rules like no-floating-promises that need type info, you may want to keep a minimal @typescript-eslint config alongside Biome for just those rules.

3. Plugin ecosystem is smaller

ESLint has a decade of community plugins. Biome is catching up, but if you rely on an obscure plugin, check first.

Pro Tip: Biome's biome check command runs lint + format in one pass — it is 2x faster than running them separately because the parse only happens once. Make it your default CI command and your local "fix-everything" script.

Pre-commit Integration

Lefthook or Husky both work. Here is the Lefthook config I use:

lefthook.yml

pre-commit:
  parallel: true
  commands:
    biome:
      glob: '*.{js,ts,jsx,tsx,json,css}'
      run: pnpm biome check --write --no-errors-on-unmatched {staged_files}
      stage_fixed: true

stage_fixed means fixes are automatically re-staged, so the commit that lands includes the formatting changes.

Editor Setup

The VS Code extension is biomejs.biome. Once installed, set it as the default formatter and enable format-on-save:

.vscode/settings.json

{
  "editor.defaultFormatter": "biomejs.biome",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  }
}

When to Wait

  • Heavy reliance on type-aware rules — stay on ESLint for those, or run both tools (Biome for everything, ESLint for the type-checker rules only)
  • Framework plugins you cannot replace — check the Biome rule catalog first
  • Monorepo with shared ESLint config across many apps — migration is straightforward but not trivial; plan a couple of days

For everyone else, I'd suggest giving Biome a serious look. Faster CI, simpler config, one less tool to keep updated.

Resources