Featured image of post Replace ESLint + Prettier with Biome: 35x Faster, One Tool

Replace ESLint + Prettier with Biome: 35x Faster, One Tool

Biome is a Rust-based frontend toolchain that formats 35x faster than Prettier, includes 455 lint rules covering ESLint + TypeScript ESLint, and replaces five config files with one biome.json. Auto-migration included.

Your project root is cluttered: .eslintrc.json, .eslintignore, .prettierrc, .prettierignore, lint-staged.config.js. Change one rule, wait five seconds for ESLint and Prettier to finish before committing. Biome is one tool, one config file, 35x faster.

What Is Biome

Biome is a Rust-based frontend toolchain that combines a formatter and linter into a single CLI. Its formatter achieves 97% compatibility with Prettier, and its linter has 455 rules covering what used to require ESLint + TypeScript ESLint + several plugins.

Supported languages: JavaScript, TypeScript, JSX, TSX, JSON, CSS, HTML, GraphQL.

AWS, Google, Microsoft, Discord, Vercel, and Cloudflare all use it.

Installation

1
2
3
4
5
6
7
8
# npm (-E pins the exact version for consistent behavior across machines)
npm i -D -E @biomejs/biome

# pnpm
pnpm add -D -E @biomejs/biome

# yarn
yarn add -D -E @biomejs/biome

Initialize a config file:

1
npx @biomejs/biome init

This generates biome.json:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}

Three Core Commands

1
2
3
4
5
6
7
8
# Format files
npx @biomejs/biome format --write .

# Lint and auto-fix
npx @biomejs/biome lint --write .

# Do everything: format + lint + organize imports
npx @biomejs/biome check --write .

For CI, use biome ci — it returns a non-zero exit code on issues, failing the pipeline:

1
npx @biomejs/biome ci .

biome.json Configuration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
  "$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
  "formatter": {
    "enabled": true,
    "indentStyle": "space",   // "space" or "tab"
    "indentWidth": 2,
    "lineWidth": 100
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",        // Single quotes
      "trailingCommas": "all",       // Trailing commas everywhere
      "semicolons": "asNeeded"       // No mandatory semicolons
    }
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "suspicious": {
        "noDebugger": "error"
      },
      "correctness": {
        "noUnusedVariables": {
          "level": "warn",
          "fix": "none"            // Detect but don't auto-fix
        }
      }
    }
  },
  "organizeImports": {
    "enabled": true
  },
  "files": {
    "ignore": ["dist/**", "node_modules/**", "*.min.js"]
  }
}

Language-Specific Settings

Different languages can have different rules. For example, to disable formatting for JSON:

1
2
3
4
5
6
7
{
  "json": {
    "formatter": {
      "enabled": false
    }
  }
}

Lint Rule Categories

Biome organizes rules into eight groups:

  • correctness: Guaranteed errors or dead code
  • suspicious: Likely incorrect patterns
  • style: Consistent, idiomatic code
  • complexity: Overly complex constructs
  • performance: Performance issues
  • security: Security vulnerabilities
  • a11y: Accessibility problems
  • nursery: New experimental rules (opt-in)

Disable an entire group:

1
2
3
4
5
6
7
{
  "linter": {
    "rules": {
      "a11y": "off"
    }
  }
}

Migrating from ESLint + Prettier

Biome provides automatic migration commands:

1
2
3
4
5
# Migrate from Prettier
npx @biomejs/biome migrate prettier --write

# Migrate from ESLint
npx @biomejs/biome migrate eslint --write

migrate prettier converts .prettierrc settings into Biome’s formatter config.

migrate eslint reads your .eslintrc.json (or flat config), maps what it can to Biome rules, and adds comments explaining anything it couldn’t convert.

After migration, clean up:

1
2
3
4
5
# Remove old tools
npm uninstall eslint prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-plugin-prettier

# Delete old config files
rm .eslintrc.json .eslintignore .prettierrc .prettierignore

Then run a check to verify everything works:

1
npx @biomejs/biome check --write .

Update package.json Scripts

Before:

1
2
3
4
5
6
{
  "scripts": {
    "lint": "eslint --ext .ts,.tsx src",
    "format": "prettier --write src"
  }
}

After:

1
2
3
4
5
6
7
{
  "scripts": {
    "lint": "biome lint --write .",
    "format": "biome format --write .",
    "check": "biome check --write ."
  }
}

Using with Lefthook

If you use Lefthook for Git hooks, replace Husky + lint-staged + ESLint + Prettier with:

1
2
3
4
5
6
7
# lefthook.yml
pre-commit:
  commands:
    biome:
      glob: "*.{js,ts,jsx,tsx,json,css}"
      run: npx @biomejs/biome check --write {staged_files}
      stage_fixed: true

One command replaces three tools.

Performance

Official benchmark: formatting 171,127 lines across 2,104 files on an Intel Core i7 1270P — Biome is 35x faster than Prettier.

In practice: biome check on large projects usually completes in under a second. What took 10-15 seconds with ESLint + Prettier is now nearly instant.

Caveats

Not every ESLint plugin has a Biome equivalent. If you rely on specific plugins (some eslint-plugin-import rules, for example), verify Biome covers them before migrating. Most common TypeScript ESLint rules are supported.

Test on a small project first, then roll it out to your main codebase once you’re confident.

References