
Dec 23, 2025
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.
The Traditional Setup (ESLint + Prettier)
Let's first understand the pain points that Biome solves.
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");
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"
};
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"
To fix this, the JavaScript community created eslint-config-prettierβa package that disables conflicting ESLint rules. Now your setup looks like:
ESLint for linting (finding bugs)
Prettier for formatting (fixing appearance)
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
}
}
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.
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 .
Your JavaScript Code
β
Biome Engine (Rust)
β
ββ Linter: Finds bugs
ββ Formatter: Fixes appearance
ββ Organizer: Sorts imports
β
biome.json (single config file)
β
Fixed & Formatted Code
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.
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.
Real-world benchmarks on different project sizes:
| Project Size | ESLint + Prettier | Biome | Speed Improvement |
|---|---|---|---|
| Small (45 files) | 3.2 seconds | 0.4 seconds | 8x faster |
| Medium (180 files) | 12.8 seconds | 1.1 seconds | 11.6x faster |
| Large (450+ files) | 38.4 seconds | 2.9 seconds | 13.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
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.
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
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.
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:
| Section | Purpose |
|---|---|
$schema | Helps your editor provide autocomplete for config options |
vcs | Tells Biome to respect your .gitignore file |
files | Controls which files Biome processes |
formatter | Formatting settings (indentation, line width, etc.) |
organizeImports | Automatically sorts your imports |
linter | Linting settings and rules |
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
Biome is powerful because you can customize it to match your team's preferences. Here's a deep dive into common options:
{
"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": {
"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": {
"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
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
}
}
}
}
Biome can automatically convert your existing ESLint configuration:
npx biome migrate eslint --write
This command:
Reads your .eslintrc file
Converts equivalent ESLint rules to Biome rules
Updates your biome.json automatically
Saves the mapping for reference
What happens:
Before:
- .eslintrc
- .eslintignore
- .prettierrc
- eslint-config-prettier
After:
- biome.json (with all settings converted)
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
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:
Open node_modules/eslint-config-next/index.js
Find this line (usually near the top):
require('@rushstack/eslint-patch/modern-module-resolution')
Comment it out temporarily:
// require('@rushstack/eslint-patch/modern-module-resolution')
Run migration:
npx biome migrate eslint --write
Uncomment the line (if you plan to keep ESLint)
β‘ 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
For the best development experience, install Biome's VS Code extension:
Open VS Code
Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)
Search for "Biome"
Install the official extension by Biomejs
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
Open a JavaScript file in VS Code
Make a formatting mistake (extra spaces, wrong quotes, etc.)
Press Save (Ctrl+S / Cmd+S)
Watch Biome automatically fix it! β¨
Before save:
const user={name:"John",age:30}
After save:
const user = { name: "John", age: 30 };
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
}
}
}
"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": {
"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
"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": {
"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
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 ."
}
}
# 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
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
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 .
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.
A: Biome doesn't support all ESLint plugins (it doesn't use the same plugin system). However:
Most common rules are built-in (410 rules total)
You can disable Biome rules and keep ESLint for specific rules
The plugin ecosystem is constantly growing
A: Set them to "off" in biome.json:
{
"linter": {
"rules": {
"suspicious": {
"noConsole": "off" // Disable this rule
}
}
}
}
A: Partially:
CSS: Basic linting supported
HTML: Not yet (future roadmap)
JSON: Full support β
GraphQL: Full support β
JSX/TSX: Full support β
A: Full support! Biome automatically detects .ts and .tsx files and applies appropriate rules.
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.
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
}
A: You have options:
Check Biome's GitHub issues (might be planned)
Use suppression comments
Keep ESLint for that specific rule
Request a feature
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"
}
}
}
}
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.
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.
Unified Tooling: One tool, one config file, infinite clarity
Incredible Speed: 10-20x faster than ESLint + Prettier
Zero Conflicts: No more fighting tools
Intelligent Defaults: Works great out of the box
Easy Migration: Existing projects can migrate in minutes
Modern Best Practices: Built with modern JavaScript in mind
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?
# 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 β¨
Try Biome on a new project first
Measure the performance improvements
Migrate existing projects gradually
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!
Documentation: https://biomejs.dev
GitHub Repository: https://github.com/biomejs/biome
Configuration Reference: https://biomejs.dev/reference/configuration
Community Discord: Join for help and discussions

25 Dec 2025
Top 5 Animated UI Component Libraries for Frontend Developers

24 Dec 2025
Why Most Modern Apps use Kafka

24 Dec 2025
Top 10 AI Tools Every Developer Should Know