Replacing ESLint and Prettier with Biome

Introduction: The Monolithic Linter Overhead

For nearly a decade, the standard recipe for JavaScript and TypeScript code quality has remained unchanged: run ESLint for linting syntax and catching logical errors, paired with Prettier for enforcing code style. While this duology has successfully standardized codebases, it comes with a significant performance tax.

The combination requires parsing the Abstract Syntax Tree (AST) multiple times, orchestrating multiple Node.js processes, configuring complicated integration plugins like eslint-config-prettier, and managing heavy node_modules directories. As codebases grow into monorepos with hundreds of thousands of lines of code, local pre-commit hooks and CI/CD lint pipelines slow down, introducing friction into the developer inner loop. Enter Biome: a single, ultra-fast toolchain written in Rust, designed to replace ESLint, Prettier, and more under a single configuration unified by a single AST parser.

The Performance Bottlenecks of Traditional Tooling

To understand why Biome represents a major evolutionary leap, we must dissect the execution model of ESLint and Prettier. When a developer runs a typical lint-and-format step, the following actions occur:

  • The source code is loaded into memory.
  • Prettier parses the code into its own custom AST, formats it, and writes the output back to disk.
  • ESLint parses the code again, building a separate AST (often using Espree or @typescript-eslint/parser), executes a set of AST visitor rules, and performs auto-fixes.
  • If tools like TypeScript are involved, additional type checking and AST parsing are invoked.

This process is highly inefficient because it duplicates parsing effort and relies on the V8 engine to execute JavaScript-based rules. ESLint rules are written in JavaScript, requiring dynamic evaluation and garbage collection cycles. When running across thousands of files, Node.js-based linters struggle with memory overhead and single-threaded execution limitations.

Biome, by contrast, is compiled directly to native machine code. It parses the codebase once into a unified, high-fidelity lossless CST (Concrete Syntax Tree) and runs linter and formatter operations in parallel across all available CPU cores using Rust's Rayon library. The result is a toolchain that is up to 25 times faster than Prettier and 15 times faster than ESLint.

Architectural Comparison: Single AST vs. Dual ASTs

The core innovation of Biome is its unified architecture. By maintaining a single parser and AST, Biome eliminates the synchronization errors that plague ESLint and Prettier integrations. In traditional setups, conflicts often arise where ESLint rules contradict Prettier formatting decisions.

Resolving these requires importing complex configurations such as eslint-plugin-prettier, which runs Prettier as an ESLint rule—further degrading performance. Biome solves this by design with a highly resilient parser capable of parsing invalid or incomplete syntax in real-time.

The formatter and linter access the same in-memory representation, ensuring that code style and logical rules are checked in a single pass without conflicting instructions.

Step-by-Step Migration from ESLint and Prettier

Migrating to Biome is straightforward. The first step is installing the package. Unlike the typical array of devDependencies (such as eslint, prettier, @typescript-eslint/parser, eslint-plugin-react-hooks, etc.), Biome only requires a single package installation:

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

Once installed, you initialize the default configuration file, biome.json, by running the initialization command:

npx @biomejs/biome init

This creates a biome.json file in your project root. Below is a highly technical configuration showing how to map your Prettier formatting preferences and ESLint linting rules into Biome's unified schema:

{
  "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "style": {
        "useBlockStatements": "error",
        "useNamingConvention": {
          "level": "warn",
          "options": {
            "strictCase": true
          }
        }
      },
      "correctness": {
        "noUnusedVariables": "error",
        "noUndeclaredVariables": "error"
      },
      "suspicious": {
        "noExplicitAny": "warn",
        "noDoubleEquals": "error"
      }
    }
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineEnding": "lf",
    "lineWidth": 100,
    "attributePosition": "auto"
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingComma": "all",
      "semicolons": "always",
      "arrowParentheses": "always"
    }
  }
}

In this configuration, we enable import organization, define linting severity levels for specific rules, and match formatting preferences (like single quotes and 2-space indents) that align with our previous Prettier rules. Biome provides a built-in migration utility that can read your existing .eslintrc and .prettierrc configurations and automatically output a corresponding biome.json file. To run this migration helper, execute:

npx @biomejs/biome migrate eslint --write
npx @biomejs/biome migrate prettier --write

Benchmarking the Performance Gains

In our performance testing on a production monorepo consisting of 12,400 TypeScript files (approximately 1.8 million lines of code), we compared ESLint and Prettier against Biome. The tests were executed on an AMD Ryzen 9 5950X (16 cores, 32 threads) with 64GB of RAM.

  • Prettier Formatter: Took 14.8 seconds to format all files.
  • ESLint (with TS Parser): Took 38.2 seconds to lint the codebase.
  • Combined Legacy Pipeline: Averaged 53.0 seconds when run sequentially.
  • Biome Linter & Formatter: Completed both formatting and linting in 1.9 seconds.

This represents a 27x speedup over the combined legacy pipeline. The primary driver of this speedup is the lack of V8 startup overhead for separate CLI commands and the efficient multi-threaded traversal of the directory structure. In local development environments, running linting on pre-commit hooks via lint-staged drops from several seconds to imperceptible milliseconds, removing any lag between writing code and committing it.

Integrating Biome into CI/CD Pipelines

Integrating Biome into your automated workflows is trivial due to its single-binary distribution. In your GitHub Actions workflow, you do not need complex caching strategies for the node_modules folder just to lint code. You can run the check command directly, which runs the formatter, linter, and import organizer in a single pass:

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

The ci command enforces that formatting matches, all linter rules pass, and imports are sorted. If any check fails, it exits with a non-zero status code and outputs clean, readable diffs directly to the console.

The IDE integration is similarly frictionless, with official extensions for VS Code, WebStorm, and Neovim that replace existing linter and formatter hooks, matching formatting-on-save actions to the CLI's rules in real-time.

Optimizing Edge Code Compliance with Bramsley

Verifying code quality and executing micro-builds at the global edge network layer demands a toolchain that matches our execution speeds. Bramsley integrates high-performance compilation and static analysis directly into our edge deployment pipeline.

  • Sub-Millisecond Verification: We leverage Biome's Rust-based engine to lint dynamic assets in real-time, eliminating V8 startup lag before edge workers deploy.
  • Zero-Latency Guardrails: Every Cloudflare Worker and Vercel Edge function is validated instantly, preventing runtime errors at the edge.
  • Optimized Bundle Delivery: Combining Biome's AST pruning with Bramsley's edge infrastructure guarantees minimal payload size and rapid global hydration.

Bramsley Digital Studio

Enterprise Digital Architecture

We engineer digital infrastructure that drives measurable B2B growth. Experts in Legacy System Migration and High-Performance Frontends.

Architecture Specs & Case Studies

Scale Your Operations

  • Legacy System Migration
  • Scalable Infrastructure
  • High-Performance Frontends
  • Global Edge Deployment