Console Login

Biome vs. The World: Why We Swapped Prettier & ESLint for Rust-Based Tooling on Our CI Runners

Stop Burning CPU Cycles on Slow Linters

If you are still waiting 45 seconds for your pre-commit hooks to finish, you are doing it wrong. I recently audited a client's CI pipeline in Oslo—a standard TypeScript monorepo with about 150,000 lines of code. Their npm run lint step took 3 minutes and 12 seconds. That is unacceptable. It breaks flow state. It wastes compute credits. It delays deployments.

For years, we accepted that ESLint and Prettier were the gold standard. They are excellent tools, but they were written in JavaScript for an ecosystem that has outgrown single-threaded performance limitations. Enter Biome (formerly Rome). It is written in Rust. It is aggressive. And frankly, it makes Node.js-based tooling look archaic.

In this analysis, we are cutting the fluff. We will look at why we migrated our internal build agents to Biome, how to configure it for strict compliance, and why the underlying hardware of your build server—specifically NVMe I/O—is the bottleneck you ignored.

The Architecture of Speed: Rust vs. V8

The problem with the traditional stack isn't just code parsing speed; it's the dependency hell and the startup overhead of the V8 engine. ESLint and Prettier require traversing the AST (Abstract Syntax Tree) separately. You are essentially parsing your code twice.

Biome unifies this. It formats and lints in a single pass. On our CoolVDS instances running standard KVM virtualization, we saw a reduction in CPU usage by nearly 60% compared to the legacy stack.

Benchmark: The 150k LoC Monorepo

We ran this test on a CoolVDS Performance Plan (4 vCPU, 8GB RAM, NVMe) located in our Oslo zone. We measured cold start execution times.

Toolchain Time (sec) Memory (MB)
ESLint + Prettier 192s 650MB
Biome 9s 45MB

This isn't a rounding error. This is an order of magnitude difference. When you scale this across 50 developers pushing code 10 times a day, you are saving hours of waiting time and significant electricity—something we in the Nordics care about deeply, regardless of how cheap our hydro power is.

Migration Strategy: biome.json Configuration

Moving from ESLint isn't just about uninstalling packages. You need a robust configuration that matches your team's style guide. Biome is opinionated, but configurable enough for enterprise needs.

Here is a production-ready biome.json we deploy for backend Node.js services. It enforces strict type safety and standard formatting.

{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "complexity": {
        "noExcessiveCognitiveComplexity": "error"
      },
      "correctness": {
        "noUnusedImports": "error",
        "noConstAssign": "error"
      },
      "style": {
        "noVar": "error",
        "useConst": "error"
      }
    }
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100,
    "lineEnding": "lf"
  },
  "files": {
    "ignore": ["dist", "node_modules", "coverage"]
  }
}
Pro Tip: Unlike Prettier, Biome handles import sorting natively. Remove eslint-plugin-import and eslint-plugin-simple-import-sort immediately. They are slow and redundant. One less dependency is one less security vulnerability.

Implementation: The CLI Workflow

Don't just install it globally. Pin the version in your package.json to ensure deterministic builds across your team and your CI infrastructure.

# Install Biome (Exact version recommended for stability)
npm install --save-dev --exact @biomejs/biome

# Initialize configuration
npx @biomejs/biome init

# Run the check (Lints, checks formatting, and organized imports)
npx @biomejs/biome check --apply ./src

# CI Mode (Reports errors without fixing them, exits with non-zero code on failure)
npx @biomejs/biome ci ./src

Note the --apply flag. It safely applies fixes. For more aggressive fixing (which might alter logic slightly, so use with git status clean), use --apply-unsafe.

The Hardware Bottleneck: Why I/O Matters

Here is the part most "serverless" advocates ignore. Tools like Biome are incredibly fast at processing, which means the bottleneck shifts from the CPU to the File System I/O. The tool needs to read thousands of small text files instantly.

If your build server is running on shared spinning rust (HDD) or network-throttled block storage, a Rust tool won't save you. You need high IOPS (Input/Output Operations Per Second).

At CoolVDS, we standardized on local NVMe storage for this specific reason. When a linter scans a directory tree:
1. It issues thousands of read() syscalls.
2. The kernel queues these requests.
3. The drive must respond.

On standard SSDs, latency spikes during heavy read operations (like a lint scan). On our NVMe arrays, the latency remains flat. This consistency is crucial for Jenkins or GitLab Runner nodes where multiple pipelines run concurrently.

CI/CD Integration Example (GitLab CI)

Integrating Biome into a GitLab CI pipeline is straightforward. Because it has zero dependencies (it's a single binary), you don't even need `npm install` if you cache the binary, though standard practice is to use the node modules.

stages:
  - quality

lint_code:
  stage: quality
  image: node:22-alpine
  cache:
    key: 
      files:
        - package-lock.json
    paths:
      - node_modules/
  script:
    - npm ci
    # The 'ci' command is optimized for pipeline environments
    - npx @biomejs/biome ci .
  rules:
    - if: $CI_MERGE_REQUEST_ID
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Local Nuances: Privacy & Performance

For our Norwegian clients, data sovereignty is paramount. When you run cloud-based linting services or use bloated CI SaaS providers, you often don't know where that code is being processed. By hosting your own GitLab Runners or Jenkins agents on a VPS in Norway, you ensure your intellectual property never leaves the jurisdiction. Plus, the latency from your Oslo office to a CoolVDS instance in the same region is typically under 2ms.

Speed isn't just about software; it's about physics. Distance equals latency.

Conclusion

The transition to Rust-based web tooling is not a trend; it is an inevitability. Biome provides the speed necessary to keep modern development loops tight and efficient. But remember: software is only as fast as the hardware it runs on.

If you are serious about pipeline performance, pair efficient tools like Biome with high-performance infrastructure.

Don't let your infrastructure throttle your code. Deploy a high-frequency NVMe instance on CoolVDS today and watch your build times plummet.