Biome: one tool for linting and formatting

By

Biome replaces ESLint and Prettier with one fast Rust tool. Install with biome init, run biome check, and migrate your existing config.

~~~

Biome combines formatting, linting, and import organization in one tool. It ships as a fast native binary with one configuration file.

For many JavaScript and TypeScript projects, it can replace the normal combination of ESLint and Prettier.

It does not promise to replace every plugin or support every language. The useful question is not “Is Biome faster?” The useful question is “Does Biome cover the rules and files this project needs?”

What each part does

Biome includes three closely related jobs:

The check command runs them together. We can also run format or lint separately.

One parser understands the file once and feeds the other tools. This reduces configuration overlap and prevents a formatter and linter from arguing about style.

Install Biome in the project

Add Biome as an exact development dependency:

npm install --save-dev --save-exact @biomejs/biome

The exact version keeps local development and CI on the same binary. Update it deliberately through the lockfile.

Check the installed version:

npx biome version

Create the configuration:

npx biome init

This writes biome.json in the project root.

Use biome.jsonc when you want comments:

npx biome init --jsonc

Commit the configuration and lockfile.

Start with a small configuration

Here is a practical biome.json for the style used in these examples:

{
  "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "files": {
    "includes": [
      "src/**",
      "tests/**",
      "scripts/**",
      "*.json"
    ]
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "semicolons": "asNeeded"
    }
  }
}

The schema path points at the installed package. It stays aligned with the version in node_modules without putting an exact release number in the URL.

The VCS section tells Biome to respect Git ignore files. The files.includes list defines the project surface Biome should inspect.

Start with recommended lint rules. Add rules because they catch a problem the team cares about, not because a long list looks strict.

Check the project

Run all configured checks:

npx biome check .

Without --write, Biome reports formatting differences, lint diagnostics, and import organization changes. It does not rewrite files.

This read-only form is the right first run on an existing project. It shows the size and type of the migration.

Apply formatting, import sorting, and safe fixes:

npx biome check --write .

Review the diff after any bulk write:

git diff

Biome separates safe and unsafe fixes. --write applies safe fixes. Add --unsafe only when you have reviewed what those rules may change:

npx biome check --write --unsafe .

I would never make --unsafe the automatic default in a pre-commit hook.

Run formatting alone

Check formatting without writing:

npx biome format src/

Format files:

npx biome format --write src/

The formatter is opinionated, like Prettier. A small set of options controls common preferences, but the goal is to stop debating every line break.

Biome tries to stay close to Prettier, but the output is not byte-for-byte identical in every case. Expect a formatting diff during migration.

Run linting alone

Run the linter:

npx biome lint src/

Apply safe lint fixes:

npx biome lint --write src/

Show the documentation for a rule:

npx biome explain noUnusedVariables

Diagnostics include a category such as:

lint/correctness/noUnusedVariables

Use that category when configuring or suppressing the rule.

Configure one rule

Rules are grouped by purpose. This configuration rejects console.log calls:

{
  "linter": {
    "rules": {
      "recommended": true,
      "suspicious": {
        "noConsole": "error"
      }
    }
  }
}

Rule names and groups are part of Biome’s own configuration model. An ESLint rule with a similar purpose may have another name.

Before copying a rule from a snippet, check the current Biome rule page. It shows stability, default severity, supported languages, and whether a fix is safe.

Suppress a diagnostic narrowly

Sometimes a rule is correct for the project but wrong for one line.

Use a targeted suppression with a reason:

// biome-ignore lint/suspicious/noConsole: this CLI writes its result to stdout
console.log(report)

The comment names one rule and explains the exception.

Avoid a file-wide suppression when one line is enough. Avoid disabling a recommended group because of one false positive.

Configure different folders

Tests may need rules that production code does not. Use an override:

{
  "overrides": [
    {
      "includes": ["tests/**"],
      "linter": {
        "rules": {
          "suspicious": {
            "noConsole": "off"
          }
        }
      }
    }
  ]
}

Keep overrides small. Many overlapping patterns make it hard to know which rule applies to a file.

Use the CLI to inspect failures, and keep related files under one clear configuration root.

React rules

Biome includes rules for React Hooks, including hook placement and effect dependencies.

Current Biome versions organize framework-specific rules into domains. A React project can enable the recommended React domain:

{
  "linter": {
    "domains": {
      "react": "recommended"
    }
  }
}

This covers important common rules, but it does not mean every rule from every React ESLint plugin exists.

Compare the exact plugins and rules used by the project before removing ESLint. Framework plugins can encode knowledge that a general-purpose linter does not have yet.

Migrate from Prettier

Commit or stash your work before a migration. Then start from a clean tree so the generated diff is easy to review.

Ask Biome to read the Prettier configuration:

npx biome migrate prettier --write

Biome maps supported settings into biome.json. Its defaults differ from Prettier in areas such as tabs and semicolons, so migration is better than assuming the defaults match.

Run a formatting check next:

npx biome format .

Then format on a branch and review the complete diff:

npx biome format --write .

Biome does not format every language or framework Prettier supports. Keep Prettier for uncovered files when needed. A gradual migration is valid.

Migrate from ESLint

Biome can read legacy and flat ESLint configuration:

npx biome migrate eslint --write

The migration understands several popular plugin rule sets and maps supported rules into Biome names.

It cannot reproduce arbitrary JavaScript inside an ESLint config, custom rules, processors, or every plugin behavior. Current Biome documentation also notes configuration-format limits, so check the migration guide for the config used by your project.

Compare the actual enabled rules before uninstalling anything:

  1. Run the current ESLint command and save its result
  2. Run the Biome migration
  3. Run biome check without writing
  4. Review unsupported and changed rules
  5. Keep ESLint for gaps that matter
  6. Remove old dependencies only after CI passes

Using both tools temporarily is better than silently losing a security or framework rule.

Add package scripts

Give local development and CI stable commands:

{
  "scripts": {
    "check": "biome check .",
    "check:write": "biome check --write .",
    "ci": "biome ci ."
  }
}

Run the local check:

npm run check

Fix safe issues:

npm run check:write

The scripts pin behavior to the repository’s installed Biome version.

Use biome ci in automation

Biome provides a separate read-only command for CI:

npx biome ci .

It runs formatting, linting, and import organization checks without offering a write mode.

A GitHub Actions job can be small:

steps:
  - uses: actions/checkout@v6

  - uses: actions/setup-node@v6
    with:
      node-version: '24'
      cache: npm

  - run: npm ci
  - run: npm run ci

Do not let CI rewrite code and commit it automatically. CI should tell us the committed source does not meet the project rules.

For a large repository, Biome can check only changed files through its VCS integration. Start with the complete project until the rules and ignore patterns are proven.

Check staged files

Biome has a staged mode:

npx biome check --staged

This is useful in a Git hook because it focuses on the next commit.

Use the read-only command in the hook first. Automatic writes and partially staged files need careful testing, because the working-tree file may contain changes that are not part of the commit.

The Git hooks tutorial explains that staged snapshot boundary.

Editor integration

Install the official Biome extension in VS Code or Cursor. Set Biome as the default formatter for the languages the project assigns to it.

The editor and CLI must use compatible Biome versions and the same biome.json. Prefer the project’s installed binary when the extension supports that choice.

Enable format on save only after the first repository-wide formatting decision. Otherwise, one file may receive a large unrelated diff during normal work.

Run the CLI before committing even with editor integration. The CLI is the shared source of truth and covers files nobody opened.

Generated files and ignores

Do not lint build output, vendored code, or generated clients unless the project owns their source.

Use files.includes with ordered exceptions:

{
  "files": {
    "includes": [
      "**",
      "!dist/**",
      "!coverage/**",
      "!src/generated/**"
    ]
  }
}

Also enable vcs.useIgnoreFile so normal Git ignores participate.

Be explicit in monorepos. A root configuration should not accidentally scan caches or generated files inside every package.

Common Biome mistakes

Watch for these:

Biome is one tool, but it still needs a clear project policy.

When to keep ESLint or Prettier

Keep ESLint when the project relies on a custom rule, processor, or framework plugin Biome does not cover.

Keep Prettier for a file type Biome cannot format. It is fine to assign different tools to non-overlapping file sets.

Do not run two formatters over the same JavaScript files. Even small output differences create endless formatting churn.

A greenfield JavaScript or TypeScript project is the easiest place to adopt Biome. A mature repository needs a rule-by-rule migration, not a tool-name replacement.

How I use Biome

I would start with biome check on a new project and keep the recommended rules. I would add single quotes and semicolon preferences, then stop configuring until a real need appears.

For an existing project, I would migrate on a dedicated branch. I would separate the formatting-only change from behavior changes so the diff remains reviewable.

I would keep ESLint beside Biome for a missing rule instead of pretending the gap does not matter. The benefit of one tool is simplicity, but only when it still checks the things the project depends on.

Tagged: DevTools · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about devtool: