logo
Biome: The Best Alternative to Prettier and ESLint for Developers

Biome: The Best Alternative to Prettier and ESLint for Developers

Dec 23, 2025

Introduction

  • If you're a JavaScript developer working with React, Next.js, or Vue projects, you've probably spent hours wrestling with ESLint and Prettier. They're essential tools for maintaining code quality, but they often feel like they fight each other more than they help.

  • Welcome to Biome πŸš€β€”a modern alternative that simplifies your entire code quality setup.

  • In this detailed guide, we'll explore what Biome is, why it's worth adopting, and how to integrate it into your projects. Whether you're starting a new project or migrating an existing one, this guide has you covered.


Understanding the Problem

The Traditional Setup (ESLint + Prettier)

Let's first understand the pain points that Biome solves.

What is ESLint?

ESLint is a JavaScript linterβ€”a tool that analyzes your code to find bugs, performance issues, and code quality problems. It checks for things like:

  • Unused variables

  • Undefined functions

  • Logic errors

  • Best practice violations

  • Accessibility issues (in React)

Example of ESLint catching bugs:

// ❌ ESLint error: 'user' is declared but never used
const user = { name: "John" };
console.log("Hello");

What is Prettier?

Prettier is a code formatterβ€”a tool that automatically fixes how your code looks (formatting), regardless of style preferences. It handles:

  • Indentation (spaces vs tabs)

  • Quote style (single vs double quotes)

  • Line length (when to break into multiple lines)

  • Semicolons (when to use them)

  • Spacing around brackets and operators

Example of Prettier formatting:

// Before Prettier (inconsistent formatting)
const obj = {name:"John",age:30,email:"john@example.com"}

// After Prettier (consistent formatting)
const obj = {
  name: "John",
  age: 30,
  email: "john@example.com"
};

The Conflict Problem

Here's where the pain begins: ESLint and Prettier have overlapping concerns.

ESLint has formatting rules (like semicolon enforcement), and Prettier also enforces formatting. This creates conflicts:

Scenario 1: Semicolon Conflict

  • ESLint rule: "always use semicolons" (error)

  • Prettier: "I don't use semicolons" (removes them)

  • Result: You run ESLint β†’ adds semicolons β†’ save file β†’ Prettier removes them β†’ infinite loop

Scenario 2: Quote Conflict

  • ESLint rule: "use single quotes" (error)

  • Prettier: "I prefer double quotes" (changes them)

  • Result: Your code quality checks fail even though your code is "formatted"


The Solution: Install More Tools!

To fix this, the JavaScript community created eslint-config-prettierβ€”a package that disables conflicting ESLint rules. Now your setup looks like:

  1. ESLint for linting (finding bugs)

  2. Prettier for formatting (fixing appearance)

  3. eslint-config-prettier for resolving conflicts

This means 3 different tools, 3 different configuration files (.eslintrc, .prettierrc, .prettierignore), and lots of package dependencies.

Real example from your package.json:

{
  "devDependencies": {
    "eslint": "^8.0.0",
    "prettier": "^3.0.0",
    "eslint-config-prettier": "^9.0.0",
    "eslint-plugin-react": "^7.0.0",
    "eslint-plugin-react-hooks": "^4.0.0",
    "@typescript-eslint/eslint-plugin": "^6.0.0",
    "@typescript-eslint/parser": "^6.0.0"
    // ... dozens more packages
  }
}

What is Biome?

Biome is a single tool that combines the functionality of ESLint, Prettier, and more into one unified toolchain. Written in Rust (a fast programming language), it eliminates the complexity of managing multiple tools.


Key Characteristics

1. All-in-One Toolchain

  • Linter (finds bugs) βœ“

  • Formatter (fixes appearance) βœ“

  • Import organizer (sorts imports) βœ“

  • All in one tool

2. Blazingly Fast
Because it's written in Rust and uses multi-threading, Biome is 10-20x faster than ESLint + Prettier:

ESLint + Prettier on 450 files: 38 seconds
Biome on 450 files: 2.9 seconds
Speed improvement: 13x faster!

3. Intelligent by Default
Biome comes with smart defaults:

  • Knows about React and TypeScript

  • Enforces modern JavaScript best practices

  • Understands your project structure automatically

4. Zero Configuration (Really!)
Unlike ESLint which requires complex setups, Biome works out of the box:

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

# Initialize
npx biome init

# Start linting and formatting immediately!
npx biome check --write .

How Biome Works

Your JavaScript Code
        ↓
    Biome Engine (Rust)
        ↓
    β”œβ”€ Linter: Finds bugs
    β”œβ”€ Formatter: Fixes appearance
    └─ Organizer: Sorts imports
        ↓
    biome.json (single config file)
        ↓
    Fixed & Formatted Code

Why Switch to Biome?

1. One Configuration File

Before (ESLint + Prettier):

project/
β”œβ”€β”€ .eslintrc.json
β”œβ”€β”€ .eslintignore
β”œβ”€β”€ .prettierrc
β”œβ”€β”€ .prettierignore
└── eslint-config-prettier

After (Biome):

project/
└── biome.json

A single biome.json file handles everything. No more hunting through multiple configuration files.

What a Biome config looks like:

{
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}

Simple, readable, and complete.


2. Zero Config Defaults

Biome automatically enables recommended linting rules:

  • no-unused-vars: Catches variables you forget to use

  • useExhaustiveDependencies: Prevents React hook bugs

  • noConsoleLog: Reminds you to remove debug logging

  • And 400+ more rules

You don't need to research and manually enable each ruleβ€”Biome knows what matters.


3. Incredible Speed

Real-world benchmarks on different project sizes:

Project SizeESLint + PrettierBiomeSpeed Improvement
Small (45 files)3.2 seconds0.4 seconds8x faster
Medium (180 files)12.8 seconds1.1 seconds11.6x faster
Large (450+ files)38.4 seconds2.9 seconds13.2x faster

What this means for your workflow:

  • Pre-commit hooks complete instantly instead of waiting 5-10 seconds

  • CI/CD pipelines finish in minutes instead of waiting 30+ minutes

  • Daily development feels snappier and more responsive


4. Better Error Messages

Biome's error messages are clear and actionable:

❌ Biome ERROR (typical ESLint)
42:10  error  'user' is assigned a value but never used  no-unused-vars

βœ… Biome ERROR (Biome's version)
file.js:42:10: error
  42 β”‚ const user = { name: "John" };
     β”‚       ^^^^
  43 β”‚ console.log("Hello");
     β”‚
  This variable is never used in your code.
  Safe fix: Remove the unused variable.

Clear, contextualized, actionable.


5. Unified Development Experience

No more context switching between tools:

# ESLint + Prettier approach (run multiple commands)
npm run lint
npm run format
npm run lint-fix

# Biome approach (one command)
npm run check  # Lints AND formats in one command

Getting Started: Installation

Step 1: Install Biome Package

Choose your package manager and run:

Using npm:

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

Using yarn:

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

Using pnpm:

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

The --save-exact flag is importantβ€”it locks to the exact version to ensure consistency across your team.


Step 2: Initialize Configuration

Create your initial configuration file:

npx biome init

This command creates a biome.json file in your project root with sensible defaults:

{
  "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
  "vcs": {
    "enabled": false,
    "clientKind": "git",
    "useIgnoreFile": false
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": []
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "tab",
    "lineWidth": 80
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}

What each section means:

SectionPurpose
$schemaHelps your editor provide autocomplete for config options
vcsTells Biome to respect your .gitignore file
filesControls which files Biome processes
formatterFormatting settings (indentation, line width, etc.)
organizeImportsAutomatically sorts your imports
linterLinting settings and rules

Step 3: Test It Out

Try running Biome on your project:

# Check what issues Biome finds (without fixing)
npx biome check .

# Check and automatically fix issues
npx biome check --write .

# Just format (without linting)
npx biome format --write .

# Just lint (without formatting)
npx biome lint --apply .

You should see output showing:

  • Files processed

  • Issues found

  • Fixes applied


Configuration Guide

Understanding Configuration Options

Biome is powerful because you can customize it to match your team's preferences. Here's a deep dive into common options:

Formatter Configuration

{
  "formatter": {
    "enabled": true,
    "indentStyle": "space",      // "space" or "tab"
    "indentWidth": 2,             // Number of spaces (if using spaces)
    "lineWidth": 100,             // Max characters per line
    "lineEnding": "lf"            // "lf" (Unix) or "crlf" (Windows)
  }
}

Real-world example:

// If lineWidth is 80
const user = { name: "John", age: 30, email: "john@example.com" };

// Biome automatically breaks it into multiple lines
const user = {
  name: "John",
  age: 30,
  email: "john@example.com"
};

JavaScript-Specific Formatting

{
  "javascript": {
    "formatter": {
      "quoteStyle": "single",         // Single or double quotes
      "trailingCommas": "es5",        // When to add trailing commas
      "semicolons": "always",         // Always, never, or asNeeded
      "arrowParentheses": "always",   // (x) => {} or x => {}
      "bracketSpacing": true,         // { x } or {x}
      "bracketSameLine": false        // > on same line or new line
    }
  }
}

Visual example:

// With recommended settings
const map = (x) => ({ value: x });
const obj = { name: "John" };
const items = [1, 2, 3,];  // trailing comma

Linter Rules Configuration

{
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,        // Enable Biome's recommended rules
      "complexity": {
        "noUselessFragments": "warn"  // Warning, not error
      },
      "style": {
        "noParameterAssign": "off",   // Disable this rule
        "useNamingConvention": "off"
      },
      "correctness": {
        "noUnusedVariables": "warn"   // Warn instead of error
      }
    }
  }
}

Rule severity levels:

  • "error": Build fails, must fix

  • "warn": Shows warning, build passes

  • "off": Rule disabled


Common Configuration Scenarios

Scenario 1: New React Project

{
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "linter": {
    "rules": {
      "recommended": true,
      "correctness": {
        "useExhaustiveDependencies": "error"  // Critical for React hooks
      }
    }
  }
}

Scenario 2: Strict Enterprise Project

{
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 80,
    "semicolons": "always"
  },
  "linter": {
    "rules": {
      "recommended": true,
      "security": {
        "noDangerouslySetInnerHtml": "error"
      },
      "a11y": {
        "useValidAnchor": "error"
      }
    }
  }
}

Scenario 3: Lenient Startup

{
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2
  },
  "linter": {
    "rules": {
      "recommended": true,
      "suspicious": {
        "noConsole": "off"  // Allow console logs during development
      },
      "style": {
        "useNamingConvention": "off"  // Flexible naming
      }
    }
  }
}

Migrating from ESLint & Prettier

Option 1: Automatic Migration (Recommended)

Biome can automatically convert your existing ESLint configuration:

npx biome migrate eslint --write

This command:

  1. Reads your .eslintrc file

  2. Converts equivalent ESLint rules to Biome rules

  3. Updates your biome.json automatically

  4. Saves the mapping for reference

What happens:

Before:
- .eslintrc
- .eslintignore
- .prettierrc
- eslint-config-prettier

After:
- biome.json (with all settings converted)

Option 2: Manual Migration

If automatic migration doesn't work perfectly, migrate manually:

Step 1: Identify your ESLint rules

// .eslintrc
{
  "extends": ["eslint:recommended"],
  "rules": {
    "no-console": "warn",
    "no-unused-vars": "error"
  }
}

Step 2: Convert to Biome

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

Step 3: Test thoroughly

# Run Biome on your entire codebase
npx biome check .

# Compare with your old tools
npm run lint   # Old ESLint
npx biome lint # New Biome

Handling Migration Errors

Error: "Calling module was not recognized"

This common error occurs with Next.js projects:

βœ– Migration has encountered an error: `node` was invoked to resolve...
Error: Failed to patch ESLint because the calling module was not recognized.

Why it happens: Next.js patches ESLint with special module resolution logic.

Solution:

  1. Open node_modules/eslint-config-next/index.js

  2. Find this line (usually near the top):

    require('@rushstack/eslint-patch/modern-module-resolution')
    
  3. Comment it out temporarily:

    // require('@rushstack/eslint-patch/modern-module-resolution')
    
  4. Run migration:

    npx biome migrate eslint --write
    
  5. Uncomment the line (if you plan to keep ESLint)


Complete Migration Checklist

β–‘ Install Biome: npm install --save-dev @biomejs/biome
β–‘ Initialize: npx biome init
β–‘ Backup: Save your .eslintrc and .prettierrc
β–‘ Migrate: npx biome migrate eslint --write
β–‘ Test: npx biome check . (should pass)
β–‘ Update scripts in package.json
β–‘ Remove old tools: npm uninstall eslint prettier
β–‘ Update your CI/CD to use Biome
β–‘ Commit and deploy

VS Code Setup

Install the Biome Extension

For the best development experience, install Biome's VS Code extension:

  1. Open VS Code

  2. Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)

  3. Search for "Biome"

  4. Install the official extension by Biomejs

Configure VS Code Settings

Create a .vscode/settings.json file in your project root:

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

What this does:

  • Sets Biome as your default formatter

  • Automatically fixes code on save

  • Organizes imports on save

Testing VS Code Integration

  1. Open a JavaScript file in VS Code

  2. Make a formatting mistake (extra spaces, wrong quotes, etc.)

  3. Press Save (Ctrl+S / Cmd+S)

  4. Watch Biome automatically fix it! ✨

Before save:

const user={name:"John",age:30}

After save:

const user = { name: "John", age: 30 };

Production-Ready Configuration

Recommended biome.json for Production

Here's a battle-tested configuration used in production React applications:

{
  "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "files": {
    "ignoreUnknown": false
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100,
    "lineEnding": "lf"
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "a11y": {
        "useValidAnchor": "off",
        "noLabelWithoutControl": "off"
      },
      "complexity": {
        "noUselessFragments": "warn"
      },
      "style": {
        "noParameterAssign": "off",
        "useNamingConvention": "off"
      },
      "correctness": {
        "noUnusedVariables": "warn",
        "noChildrenProp": "off",
        "useExhaustiveDependencies": "off"
      },
      "suspicious": {
        "noConsole": "off",
        "noArrayIndexKey": "off",
        "noDuplicateJsxProps": "warn"
      }
    }
  },
  "assist": {
    "enabled": true,
    "actions": {
      "source": {
        "organizeImports": "on"
      }
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingCommas": "es5",
      "semicolons": "always",
      "arrowParentheses": "always",
      "bracketSpacing": true,
      "bracketSameLine": false
    }
  }
}

Understanding Each Section

VCS Configuration

"vcs": {
  "enabled": true,
  "clientKind": "git",
  "useIgnoreFile": true
}
  • enabled: Biome respects your VCS (Git)

  • clientKind: Uses Git (supports other VCS too)

  • useIgnoreFile: Respects .gitignore file

Benefit: Biome won't try to lint node_modules/ or other ignored files.

Formatter Configuration

"formatter": {
  "enabled": true,
  "indentStyle": "space",
  "indentWidth": 2,
  "lineWidth": 100,
  "lineEnding": "lf"
}
  • indentStyle: Use spaces (more compatible) instead of tabs

  • indentWidth: 2 spaces per indentation level (React standard)

  • lineWidth: 100 characters per line (wider than default 80)

  • lineEnding: Unix line endings (LF) for consistency across OS

Linter Rules

"off" rules (disabled):

  • noConsole: Allows console logs (useful during development)

  • useValidAnchor: Less strict accessibility

  • noParameterAssign: Allow modifying function parameters

  • noChildrenProp: Allow passing children as props

"warn" rules (warnings, not errors):

  • noUnusedVariables: Warns about unused variables

  • noDuplicateJsxProps: Warns about duplicate props in JSX

  • noUselessFragments: Warns about unnecessary fragments

These are warnings because they're helpful but not always critical.

JavaScript Formatter

"javascript": {
  "formatter": {
    "quoteStyle": "single",
    "trailingCommas": "es5",
    "semicolons": "always",
    "arrowParentheses": "always",
    "bracketSpacing": true,
    "bracketSameLine": false
  }
}

Visual examples:

// quoteStyle: "single"
const name = 'John';  // βœ“ Correct

// trailingCommas: "es5"
const items = [1, 2, 3,];  // βœ“ Added trailing comma

// semicolons: "always"
const x = 5;  // βœ“ Semicolon added

// arrowParentheses: "always"
const fn = (x) => x * 2;  // βœ“ Always includes parentheses

// bracketSpacing: true
const obj = { name: 'John' };  // βœ“ Spaces inside brackets

// bracketSameLine: false
const obj = {
  name: 'John'
};  // βœ“ Closing bracket on new line

Running Biome in Your Project

Update package.json Scripts

Replace your old linting and formatting scripts:

Before (ESLint + Prettier):

{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix",
    "format": "prettier --write .",
    "check": "npm run lint && npm run format"
  }
}

After (Biome):

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

Common Commands

# Check for issues (don't fix)
npm run check

# Check and automatically fix issues
npm run check -- --write

# Just format code
npm run format

# Just lint code
npm run lint

# Lint and fix
npm run lint:fix

# Format specific file
biome format --write src/App.jsx

# Format entire directory
biome format --write src/

# Check a single file
biome check src/utils/helpers.js

Setting Up Pre-commit Hooks

Use Husky to run Biome before each commit:

Step 1: Install Husky

npm install husky --save-dev
npx husky install

Step 2: Create pre-commit hook

npx husky add .husky/pre-commit "biome check --staged"

This runs Biome on only the files you're committing, saving time.

Step 3: Test it

# Make changes to a file
echo "const x =    5" > src/test.js

# Stage the change
git add src/test.js

# Try to commit
git commit -m "test"

# Biome will check the file and potentially prevent commit if there are issues

CI/CD Integration

GitHub Actions:

name: Code Quality

on: [push, pull_request]

jobs:
  biome:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 18
      - run: npm install
      - run: npx biome ci .

GitLab CI:

lint:
  image: node:18
  script:
    - npm install
    - npx biome ci .

FAQ and Troubleshooting

Q: Will Biome break my existing ESLint setup?

A: Only if you use ESLint plugins that Biome doesn't support. Common plugins are supported:

  • eslint-plugin-react βœ“

  • eslint-plugin-react-hooks βœ“

  • @typescript-eslint βœ“

  • eslint-plugin-next βœ“

Niche plugins may need custom configuration.

Q: Can I use Biome with my favorite ESLint plugin?

A: Biome doesn't support all ESLint plugins (it doesn't use the same plugin system). However:

  1. Most common rules are built-in (410 rules total)

  2. You can disable Biome rules and keep ESLint for specific rules

  3. The plugin ecosystem is constantly growing

Q: How do I disable specific Biome rules?

A: Set them to "off" in biome.json:

{
  "linter": {
    "rules": {
      "suspicious": {
        "noConsole": "off"  // Disable this rule
      }
    }
  }
}

Q: Does Biome support CSS or HTML?

A: Partially:

  • CSS: Basic linting supported

  • HTML: Not yet (future roadmap)

  • JSON: Full support βœ“

  • GraphQL: Full support βœ“

  • JSX/TSX: Full support βœ“

Q: What about TypeScript support?

A: Full support! Biome automatically detects .ts and .tsx files and applies appropriate rules.

Q: Can I gradually migrate to Biome?

A: Yes! You can run both tools side-by-side:

{
  "scripts": {
    "lint:old": "eslint .",
    "lint:new": "biome check .",
    "lint": "npm run lint:new"
  }
}

Run both to compare results, then fully switch when confident.

Q: How do I suppress Biome warnings for a specific line?

A: Use inline comments:

// Disable for one line
// biome-ignore lint/suspicious/noConsole: Debug info
console.log("Debug");

// Disable for a block
/* biome-ignore lint */
function legacyCode() {
  // Old code that violates modern rules
}

Q: What if Biome doesn't support my specific use case?

A: You have options:

  1. Check Biome's GitHub issues (might be planned)

  2. Use suppression comments

  3. Keep ESLint for that specific rule

  4. Request a feature

Q: Does Biome work with Next.js?

A: Absolutely! Next.js projects work great with Biome. Just handle the migration error mentioned earlier.

Typical Next.js setup:

{
  "linter": {
    "rules": {
      "recommended": true,
      "correctness": {
        "useExhaustiveDependencies": "warn"
      }
    }
  }
}

Q: How do I update Biome to the latest version?

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

It's important to use the --save-exact flag initially to lock versions, but you can update when ready.


Conclusion

Summary

Biome represents a significant step forward in JavaScript tooling. By combining linting, formatting, and import organization into a single, blazingly-fast tool, it eliminates the configuration nightmare that has plagued JavaScript developers for years.

Key Takeaways

  1. Unified Tooling: One tool, one config file, infinite clarity

  2. Incredible Speed: 10-20x faster than ESLint + Prettier

  3. Zero Conflicts: No more fighting tools

  4. Intelligent Defaults: Works great out of the box

  5. Easy Migration: Existing projects can migrate in minutes

  6. Modern Best Practices: Built with modern JavaScript in mind

Why You Should Try Biome

If you answer "yes" to any of these, Biome is for you:

  • Do you spend time configuring ESLint and Prettier?

  • Does your CI/CD pipeline waste time on linting?

  • Do you get frustrated with tool conflicts?

  • Do you want to improve developer experience?

  • Are you starting a new JavaScript project?

Getting Started Today

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

# 2. Initialize
npx biome init

# 3. Start linting and formatting
npm run check

# 4. Enjoy clean code with zero headaches ✨

Next Steps

  1. Try Biome on a new project first

  2. Measure the performance improvements

  3. Migrate existing projects gradually

  4. Share your feedback with the community

The JavaScript community is moving toward simpler, faster tooling. Biome is leading that charge. Don't get left behind!


Resources