Biome 2.0 Arrives - Ultra-Fast Toolchain Replacing ESLint/Prettier

2025.12.02

Biome is an ultra-fast JavaScript/TypeScript toolchain written in Rust. It integrates the functionality of ESLint and Prettier into one tool, improving the development experience with overwhelming speed. In 2025, with the release of Biome 2.0, adoption in more projects is progressing.

What is Biome

Toolchain Comparison

flowchart TB
    subgraph Traditional["Traditional setup"]
        Workflow1["Development Workflow"]
        ESLint["ESLint<br/>(JavaScript)"]
        Prettier["Prettier<br/>(JavaScript)"]
        TSC["TypeScript<br/>tsc"]
        Config1["Multiple config files needed<br/>(.eslintrc, .prettierrc, tsconfig.json)"]

        Workflow1 --> ESLint
        Workflow1 --> Prettier
        Workflow1 --> TSC
        ESLint --> Config1
        Prettier --> Config1
        TSC --> Config1
    end
flowchart TB
    subgraph BiomeArch["Biome setup"]
        Workflow2["Development Workflow"]
        Biome["Biome (Rust)<br/>✓ Linter<br/>✓ Formatter<br/>✓ Import Sort"]
        Config2["Managed with single biome.json"]

        Workflow2 --> Biome --> Config2
    end

Performance Comparison

Tool1000 File ProcessingMemory Usage
ESLint + Prettier~30 seconds~500MB
Biome~0.5 seconds~50MB

About 60x faster, 1/10 memory

Installation and Setup

Basic Installation

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

# pnpm
pnpm add --save-dev --save-exact @biomejs/biome

# yarn
yarn add --dev --exact @biomejs/biome

# bun
bun add --dev --exact @biomejs/biome

# Initialize config file
npx @biomejs/biome init

Basic Configuration File

// biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingCommas": "all",
      "semicolons": "always"
    }
  }
}

package.json Script Configuration

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

Detailed Configuration

Complete Configuration Example

{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "files": {
    "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.js", "src/**/*.jsx"],
    "ignore": [
      "node_modules",
      "dist",
      "build",
      ".next",
      "coverage",
      "*.min.js"
    ]
  },
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "complexity": {
        "noExcessiveCognitiveComplexity": {
          "level": "warn",
          "options": {
            "maxAllowedComplexity": 15
          }
        },
        "noForEach": "warn"
      },
      "correctness": {
        "noUnusedVariables": "error",
        "noUnusedImports": "error",
        "useExhaustiveDependencies": "warn"
      },
      "performance": {
        "noAccumulatingSpread": "warn",
        "noDelete": "warn"
      },
      "security": {
        "noDangerouslySetInnerHtml": "error"
      },
      "style": {
        "noNonNullAssertion": "warn",
        "useConst": "error",
        "useTemplate": "error",
        "noParameterAssign": "error"
      },
      "suspicious": {
        "noExplicitAny": "warn",
        "noConsoleLog": "warn",
        "noDebugger": "error"
      },
      "nursery": {
        "useSortedClasses": {
          "level": "warn",
          "options": {
            "attributes": ["className", "class"],
            "functions": ["clsx", "cn", "cva"]
          }
        }
      }
    }
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineEnding": "lf",
    "lineWidth": 100,
    "attributePosition": "auto"
  },
  "javascript": {
    "formatter": {
      "enabled": true,
      "quoteStyle": "single",
      "jsxQuoteStyle": "double",
      "quoteProperties": "asNeeded",
      "trailingCommas": "all",
      "semicolons": "always",
      "arrowParentheses": "always",
      "bracketSpacing": true,
      "bracketSameLine": false
    },
    "parser": {
      "unsafeParameterDecoratorsEnabled": true
    }
  },
  "json": {
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentWidth": 2,
      "lineWidth": 100
    }
  },
  "css": {
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentWidth": 2,
      "lineWidth": 100,
      "quoteStyle": "double"
    },
    "linter": {
      "enabled": true
    }
  },
  "overrides": [
    {
      "include": ["*.test.ts", "*.test.tsx", "*.spec.ts"],
      "linter": {
        "rules": {
          "suspicious": {
            "noExplicitAny": "off"
          }
        }
      }
    },
    {
      "include": ["*.config.js", "*.config.ts"],
      "linter": {
        "rules": {
          "style": {
            "noDefaultExport": "off"
          }
        }
      }
    }
  ]
}

Linter Rule Categories

Rule Category List

CategoryRuleDescription
a11y (Accessibility)useAltTextRequire alt attribute on images
useKeyWithClickEventsKey operation on click
complexity (Complexity)noBannedTypesDetect use of banned types
noForEachRecommend for…of over forEach
noExcessiveCognitiveComplexityComplexity limit
correctness (Correctness)noUnusedVariablesDetect unused variables
noUnusedImportsDetect unused imports
useExhaustiveDependenciesuseEffect deps array
performance (Performance)noAccumulatingSpreadProhibit cumulative spread
noDeleteWarn on delete operator usage
security (Security)noDangerouslySetInnerHtmlDetect XSS vulnerability
noGlobalEvalProhibit eval() usage
style (Style)useConstUse const for non-reassigned variables
useTemplateTemplate literals over concatenation
noParameterAssignProhibit parameter reassignment
suspicious (Suspicious Code)noExplicitAnyWarn on any type usage
noConsoleLogWarn on console.log usage
noDebuggerProhibit debugger statement

Detailed Rule Configuration Example

{
  "linter": {
    "rules": {
      "correctness": {
        "useExhaustiveDependencies": {
          "level": "warn",
          "options": {
            "hooks": [
              {
                "name": "useQuery",
                "stableResult": [1]
              },
              {
                "name": "useMutation",
                "stableResult": [1]
              },
              {
                "name": "useCustomHook",
                "closureIndex": 0,
                "dependenciesIndex": 1
              }
            ]
          }
        }
      }
    }
  }
}

Migration from ESLint/Prettier

Migration Checklist

# 1. Install Biome
npm install --save-dev @biomejs/biome

# 2. Initialize config file
npx @biomejs/biome init

# 3. Auto-migrate from ESLint config
npx @biomejs/biome migrate eslint --write

# 4. Auto-migrate from Prettier config
npx @biomejs/biome migrate prettier --write

ESLint Rule Mapping Table

ESLintBiomeCategory
no-unused-varsnoUnusedVariablescorrectness
no-consolenoConsoleLogsuspicious
eqeqeqnoDoubleEqualssuspicious
prefer-constuseConststyle
no-varnoVarstyle
@typescript-eslint/no-explicit-anynoExplicitAnysuspicious
react-hooks/exhaustive-depsuseExhaustiveDependenciescorrectness
jsx-a11y/alt-textuseAltTexta11y

Gradual Migration Strategy

// biome.json - Configuration for gradual migration
{
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      // Warnings only at first
      "correctness": {
        "noUnusedVariables": "warn",
        "noUnusedImports": "warn"
      },
      "suspicious": {
        "noExplicitAny": "warn",
        "noConsoleLog": "off"  // Disabled at first
      }
    }
  }
}
# Remove ESLint/Prettier after migration
npm uninstall eslint prettier eslint-config-prettier eslint-plugin-*

# Delete config files
rm .eslintrc* .prettierrc* .eslintignore .prettierignore

Editor Integration

VS Code

// .vscode/extensions.json
{
  "recommendations": ["biomejs.biome"]
}
// .vscode/settings.json
{
  // Set Biome as default formatter
  "editor.defaultFormatter": "biomejs.biome",
  "[javascript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[json]": {
    "editor.defaultFormatter": "biomejs.biome"
  },

  // Auto-format on save
  "editor.formatOnSave": true,

  // Run code actions on save
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  },

  // Disable ESLint/Prettier
  "eslint.enable": false,
  "prettier.enable": false
}

Neovim (nvim-lspconfig)

-- init.lua
require('lspconfig').biome.setup({
  cmd = { 'npx', 'biome', 'lsp-proxy' },
  root_dir = require('lspconfig.util').root_pattern('biome.json', 'biome.jsonc'),
  single_file_support = false,
})

-- Integration with null-ls.nvim
local null_ls = require('null-ls')
null_ls.setup({
  sources = {
    null_ls.builtins.formatting.biome,
    null_ls.builtins.diagnostics.biome,
  },
})

JetBrains IDE (WebStorm, etc.)

Setup steps:
1. Settings → Languages & Frameworks → JavaScript → Code Quality Tools → Biome
2. Check "Enable"
3. Biome package: node_modules/@biomejs/biome
4. Configuration file: biome.json

Format settings:
1. Settings → Editor → Code Style
2. Turn off "Enable EditorConfig support"
3. Settings → Tools → Actions on Save
4. Check "Reformat code" and "Run Biome"

CI/CD Integration

GitHub Actions

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run Biome CI
        run: npx @biomejs/biome ci .

  # Add inline annotations to PR
  lint-review:
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4

      - name: Setup Biome
        uses: biomejs/setup-biome@v2
        with:
          version: latest

      - name: Run Biome with reviewdog
        uses: reviewdog/action-biome@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          reporter: github-pr-review

GitLab CI

# .gitlab-ci.yml
stages:
  - lint

biome:
  stage: lint
  image: node:20-alpine
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
  script:
    - npm ci
    - npx @biomejs/biome ci .
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

pre-commit Hook (Husky + lint-staged)

# Install Husky
npm install --save-dev husky lint-staged
npx husky init
// package.json
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx,json,css}": [
      "biome check --write --no-errors-on-unmatched"
    ]
  }
}
# .husky/pre-commit
npx lint-staged

Advanced Usage

Plugin API (Experimental Feature)

// biome-plugin.js - Custom rule example
export default {
  name: 'my-custom-rules',
  rules: {
    noTodoComments: {
      meta: {
        docs: {
          description: 'Disallow TODO comments in production code',
        },
      },
      create(context) {
        return {
          Comment(node) {
            if (node.value.includes('TODO')) {
              context.report({
                node,
                message: 'TODO comments should be resolved before merge',
              });
            }
          },
        };
      },
    },
  },
};

Monorepo Configuration

// Root biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "extends": [],
  "files": {
    "ignore": ["packages/*/dist", "packages/*/node_modules"]
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "formatter": {
    "enabled": true
  }
}
// packages/web/biome.json - Package-specific config
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "extends": ["../../biome.json"],
  "linter": {
    "rules": {
      "correctness": {
        "useExhaustiveDependencies": "warn"
      }
    }
  }
}

Custom Import Sorting

{
  "javascript": {
    "organizeImports": {
      "groups": [
        ["react", "react-dom"],
        ["^@?\\w"],
        ["^@/"],
        ["^\\.\\."],
        ["^\\."]
      ]
    }
  }
}

Troubleshooting

Common Issues and Solutions

# Clear cache
rm -rf node_modules/.cache/biome

# Verbose error output
npx @biomejs/biome check --verbose .

# Debug specific file
npx @biomejs/biome lint --verbose src/problematic-file.ts

# Validate config
npx @biomejs/biome check --config-path biome.json --verbose

Error Suppression Comments

// Disable specific rule for entire file
// biome-ignore-all lint/suspicious/noExplicitAny: Legacy code

// Disable for next line only
// biome-ignore lint/suspicious/noExplicitAny: Necessary for this API
const data: any = response.data;

// Disable multiple rules
// biome-ignore lint/style/useConst lint/correctness/noUnusedVariables: Intentional
let unusedVar = 'test';

// Disable formatting
// biome-ignore format: Keep this formatting
const matrix = [
  [1, 0, 0],
  [0, 1, 0],
  [0, 0, 1],
];

Performance Benchmark

Large project comparison (10,000 files):

Toollint timeformat timeMemory usage
ESLint120s-1.2GB
Prettier-45s800MB
ESLint+Prettier165s(total)2.0GB
Biome2s1.5s150MB
Improvement60x faster30x faster13x less

Summary

Biome significantly improves the frontend development toolchain.

Benefits of Adopting Biome

ItemESLint+PrettierBiome
SpeedSlowUltra-fast (60x+)
Config filesMultiple1 file
DependenciesMany1
Memory usageLargeSmall
Config consistencyPotential conflictsIntegrated
  • New projects
  • Projects needing CI speedup
  • Teams seeking config simplification
  • Monorepo environments

Biome is becoming the new standard in the JavaScript ecosystem.

← Back to list