DEV Community

Recca Tsai
Recca Tsai

Posted on • Originally published at recca0120.github.io

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

Originally published at recca0120.github.io

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

# 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
Enter fullscreen mode Exit fullscreen mode

Initialize a config file:

npx @biomejs/biome init
Enter fullscreen mode Exit fullscreen mode

This generates biome.json:

{
  "$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Three Core Commands

# 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 .
Enter fullscreen mode Exit fullscreen mode

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

npx @biomejs/biome ci .
Enter fullscreen mode Exit fullscreen mode

biome.json Configuration

{
  "$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"]
  }
}
Enter fullscreen mode Exit fullscreen mode

Language-Specific Settings

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

{
  "json": {
    "formatter": {
      "enabled": false
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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:

{
  "linter": {
    "rules": {
      "a11y": "off"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Migrating from ESLint + Prettier

Biome provides automatic migration commands:

# Migrate from Prettier
npx @biomejs/biome migrate prettier --write

# Migrate from ESLint
npx @biomejs/biome migrate eslint --write
Enter fullscreen mode Exit fullscreen mode

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:

# 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
Enter fullscreen mode Exit fullscreen mode

Then run a check to verify everything works:

npx @biomejs/biome check --write .
Enter fullscreen mode Exit fullscreen mode

Update package.json Scripts

Before:

{
  "scripts": {
    "lint": "eslint --ext .ts,.tsx src",
    "format": "prettier --write src"
  }
}
Enter fullscreen mode Exit fullscreen mode

After:

{
  "scripts": {
    "lint": "biome lint --write .",
    "format": "biome format --write .",
    "check": "biome check --write ."
  }
}
Enter fullscreen mode Exit fullscreen mode

Using with Lefthook

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

# lefthook.yml
pre-commit:
  commands:
    biome:
      glob: "*.{js,ts,jsx,tsx,json,css}"
      run: npx @biomejs/biome check --write {staged_files}
      stage_fixed: true
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)