Back to blog
Tutorials

Ditch ESLint and Prettier: A Practical Biome Migration Guide

Kim BoenderKim Boender
April 5, 2026 6 min read
Ditch ESLint and Prettier: A Practical Biome Migration Guide

If you've ever spent 20 minutes debugging a mysterious ESLint config conflict, or watched your CI pipeline crawl through linting 10,000 files, you already know the problem I'm talking about. The JavaScript tooling ecosystem is famously fragmented, and keeping ESLint, Prettier, and all their shared plugins in sync is a tax every project eventually pays.

Biome is the most serious answer to that problem I've seen. It's a single Rust-based binary that replaces both ESLint and Prettier, and it's not just marginally faster, it's orders of magnitude faster. I've been running it on several of my TypeScript projects over the last few months, and I want to give you an honest picture of where it shines, where it still falls short (spoiler: Vue SFC support), and exactly how to migrate.

What Is Biome, Really?

Biome started as Rome Tools, a project that aimed to unify the entire JS toolchain under one roof. After Rome stalled, the community forked it and relaunched it as Biome under new stewardship. As of early 2026 it's at v2.x, ships over 400 lint rules, and has hit production-grade stability for TypeScript and JavaScript projects.

The pitch is simple: one config file, one CLI, one dependency, and performance that makes the Node.js tooling feel like it's running on a potato.

The Numbers

I'm not going to cherry-pick benchmarks, these are consistent across multiple sources:

  • Linting 10,000 files: ESLint ~45s → Biome ~0.8s
  • Formatting 10,000 files: Prettier ~12s → Biome ~0.3s

On a real-world project with a few hundred files, the difference is still dramatic. Cold linting a mid-size NestJS codebase that used to take 8-10 seconds now takes under a second. That adds up fast in a CI/CD pipeline.

Getting Started

Install Biome as a dev dependency, no global installs needed:

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

The --save-exact flag is intentional. Biome's team recommends pinning the version because formatting output is part of its API surface, you don't want unexpected formatting changes sneaking in from a minor update.

Initialize your config:

npx @biomejs/biome init

This creates a biome.json in your project root.

Configuring biome.json

Here's a solid starting config for a TypeScript project:

{
  "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "correctness": {
        "noUnusedVariables": "error",
        "noUnusedImports": "error"
      },
      "style": {
        "noNonNullAssertion": "warn",
        "useConst": "error"
      },
      "suspicious": {
        "noExplicitAny": "warn"
      }
    }
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingCommas": "all",
      "semicolons": "asNeeded"
    }
  },
  "files": {
    "ignore": [
      "node_modules",
      "dist",
      ".nuxt",
      ".output",
      "coverage"
    ]
  }
}

The organizeImports setting is a nice bonus, Biome will automatically sort and clean up your imports on format, something you'd previously need a separate ESLint plugin for.

Migrating from ESLint and Prettier

Biome ships a migration command that does a lot of the heavy lifting:

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

These commands read your existing .eslintrc and .prettierrc configs and attempt to translate the settings into biome.json. In my experience, it handles about 80-90% of common rule configurations correctly. You'll still want to manually verify the output, especially if you've got custom plugins or complex overrides.

After migration, audit what rules didn't carry over:

npx @biomejs/biome migrate eslint 2>&1 | grep -i 'unsupported\|not found'

Most "unsupported" rules are either already covered by Biome's built-in rule set under a different name, or they're things Biome intentionally doesn't have an equivalent for (usually the more opinionated formatting rules that Biome handles its own way).

Updating package.json Scripts

Swap out your old lint and format scripts:

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

I prefer using biome check as the all-in-one command, it runs linting, formatting, and import organization in one pass. It's what I wire up to pre-commit hooks and CI.

VS Code Integration

Install the official Biome VS Code extension and add this to your workspace settings:

{
  "editor.defaultFormatter": "biomejs.biome",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  }
}

Format on save just works, and the VS Code integration is genuinely solid at this point. No more fighting with eslint.validate arrays.

The Vue SFC Caveat, Read This Before Migrating

If you're primarily working on Vue projects (which, same), there's an important limitation: Biome doesn't fully support Vue Single File Components yet.

As of early 2026, .vue files have only partial support. Biome can format and lint the <script> and <script setup> blocks, but the HTML template and <style> blocks are not processed. That's a significant gap if your team relies on consistent template formatting.

The Hybrid Approach for Vue Projects

The pragmatic move for Vue projects right now is a hybrid setup:

  1. Use Biome for all your .ts, .js, and pure TypeScript files (composables, stores, utilities, API layers)
  2. Keep ESLint with eslint-plugin-vue for .vue SFC linting
  3. Keep Prettier with prettier-plugin-vue for SFC formatting (or just format the script blocks with Biome and leave templates to Prettier)

Yes, it's not the clean single-tool story, but you still get Biome's speed on the bulk of your codebase. For a Nuxt 3 project, I configure Biome to only process server/, composables/, stores/, and utils/, and let ESLint handle the components/ and pages/ directories.

You can scope Biome's coverage in biome.json:

{
  "files": {
    "include": [
      "src/**/*.ts",
      "server/**/*.ts",
      "composables/**/*.ts",
      "stores/**/*.ts",
      "utils/**/*.ts"
    ]
  }
}

Full Vue SFC support is actively being developed by the Biome team and is one of the most-requested features. Based on the pace of development, I expect meaningful progress in the second half of 2026.

CI/CD Integration

Biome is a single binary with no Node.js dependencies to resolve, which makes it genuinely fast in CI. A biome check run that includes linting and formatting in a GitHub Actions job:

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

The ci command is the right choice for pipelines, it's like check but exits with a non-zero code on any violation and doesn't write fixes. If you're deploying to Railway or Vercel, trimming CI time down matters: fewer minutes billed, faster feedback loops.

Should You Migrate Right Now?

For pure TypeScript/Node.js projects, NestJS APIs, Express servers, CLI tools, shared utility packages, yes, migrate today. The speed improvement is real, the config is dramatically simpler, and the rule coverage is solid.

For Vue 3 / Nuxt 3 projects: partial migration makes sense. Use Biome for your TypeScript layers, keep ESLint+Prettier for SFCs, and plan to cut over fully once Vue SFC support lands. The hybrid approach is worth the setup time just for the CI speed gains.

What Biome gets right, beyond performance, is the philosophy: sensible defaults that work out of the box, zero-dependency install, and a config format that doesn't require a PhD in ESLint rule taxonomy. The JavaScript toolchain has needed this for years.

Frequently Asked Questions

Is Biome a drop-in replacement for ESLint? +
Biome covers a large portion of ESLint's most common rules (over 400 total) but doesn't support the full ESLint plugin ecosystem. For standard TypeScript and JavaScript projects, it covers the vast majority of what you need. If you rely on niche ESLint plugins, check the Biome compatibility list before fully migrating.
Does Biome work with Vue Single File Components? +
Partially, as of 2026. Biome supports the script and script setup blocks in .vue files but not template or style blocks. Full SFC support is actively in development. For Vue and Nuxt projects, a hybrid approach, Biome for TypeScript files, ESLint and Prettier for SFCs, is currently the most practical path.
Can I use Biome alongside ESLint at the same time? +
Yes. You can run both tools scoped to different file types or directories using Biome's include and ignore patterns. This hybrid setup is the recommended approach for Vue projects until complete SFC support is available, and you still gain significant speed improvements on your TypeScript layers.
How does Biome handle TypeScript-specific linting rules? +
Biome has strong TypeScript support including type-aware linting introduced in v2.x, which previously required the heavy @typescript-eslint setup with a slow full type-check pass. Biome processes this significantly faster as part of its Rust-based architecture, making CI feedback much quicker.
What is the best way to enforce Biome in a team codebase? +
Combine a pre-commit hook using husky with lint-staged or lefthook with a CI check using the biome ci command. The official VS Code extension handles format on save during development, and CI acts as the enforcement safety net. Pinning the exact Biome version in package.json ensures consistent formatting output across the team.

Try it yourself

JSON Formatter

Format, validate, and beautify JSON instantly

Open JSON Formatter