Biome - Fast All-in-One Toolchain
Overview
Biome is a fast, all-in-one toolchain for web projects written in Rust. It replaces both ESLint and Prettier with a single tool that's 100x faster and provides zero-config defaults.
Key Features:
-
Single tool for linting and formatting
-
100x faster than ESLint
-
Zero configuration by default
-
Built-in import sorting
-
TypeScript-first design
-
Partial Prettier compatibility
-
Native monorepo support
-
VS Code integration
Installation:
npm install --save-dev @biomejs/biome
Quick Start
- Initialize Biome
Create biome.json configuration
npx @biomejs/biome init
Check your project
npx @biomejs/biome check .
Fix issues automatically
npx @biomejs/biome check --write .
Format only
npx @biomejs/biome format --write .
Lint only
npx @biomejs/biome lint .
- Package.json Scripts
{ "scripts": { "check": "biome check .", "check:write": "biome check --write .", "format": "biome format --write .", "lint": "biome lint .", "lint:fix": "biome lint --write ." } }
- Basic Configuration
{ "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, "files": { "ignoreUnknown": false, "ignore": ["node_modules", "dist", "build", ".next"] }, "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2, "lineWidth": 100 }, "linter": { "enabled": true, "rules": { "recommended": true } }, "javascript": { "formatter": { "quoteStyle": "single", "semicolons": "asNeeded", "trailingCommas": "all" } } }
Core Commands
Check Command (Recommended)
The check command runs both linting and formatting:
Check all files
biome check .
Fix issues automatically
biome check --write .
Unsafe fixes (may change behavior)
biome check --write --unsafe .
Apply suggested fixes
biome check --write --unsafe --apply-suggested
Check specific files
biome check src/**/*.ts
CI mode (exit with error on issues)
biome ci .
Format Command
Format code without linting:
Format all files
biome format --write .
Check formatting without changing files
biome format .
Format specific files
biome format --write src/**/*.{ts,tsx,js,jsx}
Format stdin
echo "const x={a:1}" | biome format --stdin-file-path=file.js
Lint Command
Lint code without formatting:
Lint all files
biome lint .
Fix linting issues
biome lint --write .
Show rule names
biome lint --verbose .
Apply unsafe fixes
biome lint --write --unsafe .
Configuration Deep Dive
Formatter Configuration
{ "formatter": { "enabled": true, "formatWithErrors": false, "indentStyle": "space", "indentWidth": 2, "lineEnding": "lf", "lineWidth": 80, "attributePosition": "auto" }, "javascript": { "formatter": { "quoteStyle": "single", "jsxQuoteStyle": "double", "quoteProperties": "asNeeded", "trailingCommas": "all", "semicolons": "asNeeded", "arrowParentheses": "always", "bracketSpacing": true, "bracketSameLine": false } }, "json": { "formatter": { "trailingCommas": "none" } } }
Linter Configuration
{ "linter": { "enabled": true, "rules": { "recommended": true, "a11y": { "recommended": true, "noAutofocus": "error", "useKeyWithClickEvents": "warn" }, "complexity": { "recommended": true, "noForEach": "off", "useLiteralKeys": "error" }, "correctness": { "recommended": true, "noUnusedVariables": "error", "useExhaustiveDependencies": "warn" }, "performance": { "recommended": true, "noAccumulatingSpread": "warn" }, "security": { "recommended": true, "noDangerouslySetInnerHtml": "error" }, "style": { "recommended": true, "noNonNullAssertion": "warn", "useConst": "error", "useTemplate": "warn" }, "suspicious": { "recommended": true, "noExplicitAny": "warn", "noArrayIndexKey": "error" } } } }
File Ignore Patterns
{ "files": { "ignore": [ "node_modules", "dist", "build", ".next", "coverage", ".min.js", "public/assets/" ], "ignoreUnknown": false, "include": ["src//.ts", "src/**/*.tsx"] } }
Override Configuration for Specific Files
{ "overrides": [ { "include": ["/*.test.ts", "/.spec.ts"], "linter": { "rules": { "suspicious": { "noExplicitAny": "off" } } } }, { "include": ["scripts/**/.js"], "formatter": { "lineWidth": 120 } } ] }
VS Code Integration
- Install Biome Extension
Install from VS Code marketplace
code --install-extension biomejs.biome
- VS Code Settings (.vscode/settings.json )
{ "[javascript]": { "editor.defaultFormatter": "biomejs.biome", "editor.formatOnSave": true, "editor.codeActionsOnSave": { "quickfix.biome": "explicit", "source.organizeImports.biome": "explicit" } }, "[typescript]": { "editor.defaultFormatter": "biomejs.biome", "editor.formatOnSave": true, "editor.codeActionsOnSave": { "quickfix.biome": "explicit", "source.organizeImports.biome": "explicit" } }, "[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome", "editor.formatOnSave": true }, "[json]": { "editor.defaultFormatter": "biomejs.biome", "editor.formatOnSave": true }, "biome.lspBin": "./node_modules/@biomejs/biome/bin/biome" }
- Workspace Settings
{ "editor.formatOnSave": true, "editor.formatOnPaste": true, "editor.defaultFormatter": "biomejs.biome", "biome.rename": true, "files.autoSave": "onFocusChange" }
Migration from ESLint and Prettier
- Remove Old Tools
Remove ESLint and Prettier
npm uninstall eslint prettier eslint-config-prettier
eslint-plugin-react eslint-plugin-import
@typescript-eslint/parser @typescript-eslint/eslint-plugin
Remove configuration files
rm .eslintrc.js .eslintrc.json .prettierrc .prettierignore
- Migrate Configuration
Use Biome's migration tool:
Migrate from Prettier config
biome migrate prettier --write
Migrate from ESLint config
biome migrate eslint --write
- Manual Migration
Prettier → Biome Formatter:
// .prettierrc (old) { "semi": false, "singleQuote": true, "trailingComma": "all", "printWidth": 100 }
// biome.json (new) { "formatter": { "lineWidth": 100 }, "javascript": { "formatter": { "semicolons": "asNeeded", "quoteStyle": "single", "trailingCommas": "all" } } }
ESLint → Biome Linter:
// .eslintrc.json (old) { "rules": { "no-unused-vars": "error", "prefer-const": "warn" } }
// biome.json (new) { "linter": { "rules": { "correctness": { "noUnusedVariables": "error" }, "style": { "useConst": "warn" } } } }
- Update Scripts
{ "scripts": { "lint": "biome lint .", "lint:fix": "biome lint --write .", "format": "biome format --write .", "check": "biome check --write ." } }
Git Hooks Integration
Using Husky + lint-staged
Install dependencies
npm install --save-dev husky lint-staged npx husky init
.husky/pre-commit :
#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
package.json :
{ "lint-staged": { "*.{js,ts,jsx,tsx,json}": [ "biome check --write --no-errors-on-unmatched" ] } }
Using Lefthook
lefthook.yml :
pre-commit: commands: lint: glob: "*.{js,ts,jsx,tsx,json}" run: biome check --write --no-errors-on-unmatched {staged_files}
Simple Git Hook (no dependencies)
.git/hooks/pre-commit :
#!/bin/bash
Get staged files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '.(js|ts|jsx|tsx|json)$')
if [ -n "$STAGED_FILES" ]; then echo "Running Biome on staged files..." npx @biomejs/biome check --write --no-errors-on-unmatched $STAGED_FILES
Add formatted files back to staging
git add $STAGED_FILES fi
CI/CD Integration
GitHub Actions
name: Biome CI
on: push: branches: [main, develop] pull_request: branches: [main]
jobs: biome: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run Biome CI
run: npx @biomejs/biome ci .
- name: Check formatting
run: npx @biomejs/biome format .
- name: Lint
run: npx @biomejs/biome lint .
GitLab CI
biome: image: node:20-alpine stage: test script: - npm ci - npx @biomejs/biome ci . cache: paths: - node_modules/ only: - merge_requests - main
CircleCI
version: 2.1
jobs: biome: docker: - image: cimg/node:20.11 steps: - checkout - restore_cache: keys: - deps-{{ checksum "package-lock.json" }} - run: npm ci - save_cache: paths: - node_modules key: deps-{{ checksum "package-lock.json" }} - run: npx @biomejs/biome ci .
workflows: test: jobs: - biome
Import Sorting
Biome includes built-in import sorting:
Organize imports
biome check --write --organize-imports-enabled=true .
Configuration:
{ "organizeImports": { "enabled": true } }
Example:
// Before import { useState } from 'react'; import axios from 'axios'; import { Button } from './components/Button'; import type { User } from './types'; import './styles.css';
// After (sorted) import type { User } from './types';
import axios from 'axios'; import { useState } from 'react';
import { Button } from './components/Button';
import './styles.css';
TypeScript Support
Biome has first-class TypeScript support:
{ "linter": { "rules": { "suspicious": { "noExplicitAny": "warn", "noUnsafeDeclarationMerging": "error" }, "correctness": { "noUnusedVariables": "error" }, "style": { "useImportType": "error", "useExportType": "error" } } } }
Type-aware linting:
// Biome detects unused variables const unused = 123; // ❌ Error
// Enforces type imports import { User } from './types'; // ❌ Error import type { User } from './types'; // ✅ Correct
// Detects unsafe type assertions const num = "123" as any as number; // ⚠️ Warning
Monorepo Support
Biome works great in monorepos:
Project Structure
my-monorepo/ ├── biome.json (root config) ├── packages/ │ ├── web/ │ │ └── biome.json (extends root) │ ├── api/ │ │ └── biome.json │ └── shared/ │ └── biome.json
Root Configuration
{ "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "extends": [], "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 }, "linter": { "enabled": true, "rules": { "recommended": true } } }
Package Override
{ "extends": ["../../biome.json"], "formatter": { "lineWidth": 100 }, "linter": { "rules": { "style": { "noNonNullAssertion": "off" } } } }
Monorepo Scripts
{ "scripts": { "check": "biome check .", "check:packages": "biome check packages/", "format": "biome format --write .", "lint": "biome lint packages/" } }
Performance Benefits
Speed Comparison
Tool Time (10,000 files)
ESLint + Prettier ~60s
Biome ~0.6s
100x faster on average workloads.
Caching
Biome includes intelligent caching:
First run (no cache)
biome check . # 1.2s
Second run (with cache)
biome check . # 0.1s
Clear cache
rm -rf node_modules/.cache/biome
Parallel Processing
Biome uses all CPU cores by default:
Limit CPU cores
biome check --max-diagnostics=50 .
Verbose output
biome check --verbose .
Common Patterns
React Projects
{ "linter": { "rules": { "a11y": { "recommended": true, "useButtonType": "error", "useKeyWithClickEvents": "error" }, "correctness": { "useExhaustiveDependencies": "warn", "useHookAtTopLevel": "error" }, "suspicious": { "noArrayIndexKey": "error" } } }, "javascript": { "formatter": { "jsxQuoteStyle": "double" } } }
Next.js Projects
{ "files": { "ignore": [".next", "out", "node_modules"] }, "overrides": [ { "include": ["app//*.tsx", "pages//*.tsx"], "linter": { "rules": { "a11y": { "recommended": true } } } } ] }
Node.js Backend
{ "linter": { "rules": { "security": { "recommended": true, "noGlobalEval": "error" }, "correctness": { "noUnusedVariables": "error" } } }, "javascript": { "formatter": { "semicolons": "always" } } }
Best Practices
-
Use biome check instead of separate format/lint commands
-
Enable --write flag for automatic fixes
-
Configure VS Code for format-on-save
-
Add git hooks to enforce quality before commits
-
Use CI mode (biome ci ) in continuous integration
-
Start with recommended rules then customize
-
Leverage import sorting to organize imports automatically
-
Use overrides for different file types or directories
-
Enable VCS integration to respect .gitignore
-
Keep configuration minimal - Biome has smart defaults
Troubleshooting
Biome Not Formatting
Check if formatter is enabled
biome rage
Verify file is not ignored
biome check --verbose src/file.ts
Check VS Code extension logs
View → Output → Biome
Conflicts with Prettier
Disable Prettier in VS Code settings
"[javascript]": { "editor.defaultFormatter": "biomejs.biome" }
Remove Prettier dependencies
npm uninstall prettier
Performance Issues
Check cache location
biome rage
Clear cache
rm -rf node_modules/.cache/biome
Reduce max diagnostics
biome check --max-diagnostics=20 .
Rule Configuration Not Working
// Ensure correct category { "linter": { "rules": { "correctness": { // Category name matters "noUnusedVariables": "error" } } } }
Local Biome Configs (Your Repos)
Patterns from active projects:
-
ai-code-review/biome.json : files.includes targets src/**/*.ts and excludes tests, lineWidth: 100 , single quotes, semicolons always, and noExplicitAny: warn .
-
itinerizer-ts/biome.json : files.ignore includes node_modules , dist , .claude , and data directories; organizeImports.enabled = true .
-
matsuoka-com and diogenes use similar formatting defaults (2-space indent, lineWidth 100).
Common scripts:
{ "lint": "biome check src/ --diagnostic-level=error", "lint:fix": "biome check src/ --write", "format": "biome format src/ --write" }
Resources
-
Official Docs: https://biomejs.dev
-
VS Code Extension: https://marketplace.visualstudio.com/items?itemName=biomejs.biome
-
GitHub: https://github.com/biomejs/biome
-
Rules Reference: https://biomejs.dev/linter/rules/
-
Migration Guide: https://biomejs.dev/guides/migrate-eslint-prettier/
Summary
-
Biome is a fast all-in-one linter and formatter
-
100x faster than ESLint + Prettier
-
Zero config by default with smart defaults
-
Built in Rust for maximum performance
-
TypeScript-first with excellent type support
-
Import sorting included out of the box
-
VS Code integration with official extension
-
Perfect for modern web projects, monorepos, CI/CD
-
Easy migration from ESLint and Prettier