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:
bash
1npm install --save-dev @biomejs/biome
Quick Start
1. Initialize Biome
bash
1# Create biome.json configuration
2npx @biomejs/biome init
3
4# Check your project
5npx @biomejs/biome check .
6
7# Fix issues automatically
8npx @biomejs/biome check --write .
9
10# Format only
11npx @biomejs/biome format --write .
12
13# Lint only
14npx @biomejs/biome lint .
2. Package.json Scripts
json
1{
2 "scripts": {
3 "check": "biome check .",
4 "check:write": "biome check --write .",
5 "format": "biome format --write .",
6 "lint": "biome lint .",
7 "lint:fix": "biome lint --write ."
8 }
9}
3. Basic Configuration
json
1{
2 "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
3 "vcs": {
4 "enabled": true,
5 "clientKind": "git",
6 "useIgnoreFile": true
7 },
8 "files": {
9 "ignoreUnknown": false,
10 "ignore": ["node_modules", "dist", "build", ".next"]
11 },
12 "formatter": {
13 "enabled": true,
14 "indentStyle": "space",
15 "indentWidth": 2,
16 "lineWidth": 100
17 },
18 "linter": {
19 "enabled": true,
20 "rules": {
21 "recommended": true
22 }
23 },
24 "javascript": {
25 "formatter": {
26 "quoteStyle": "single",
27 "semicolons": "asNeeded",
28 "trailingCommas": "all"
29 }
30 }
31}
Core Commands
Check Command (Recommended)
The check command runs both linting and formatting:
bash
1# Check all files
2biome check .
3
4# Fix issues automatically
5biome check --write .
6
7# Unsafe fixes (may change behavior)
8biome check --write --unsafe .
9
10# Apply suggested fixes
11biome check --write --unsafe --apply-suggested
12
13# Check specific files
14biome check src/**/*.ts
15
16# CI mode (exit with error on issues)
17biome ci .
Format code without linting:
bash
1# Format all files
2biome format --write .
3
4# Check formatting without changing files
5biome format .
6
7# Format specific files
8biome format --write src/**/*.{ts,tsx,js,jsx}
9
10# Format stdin
11echo "const x={a:1}" | biome format --stdin-file-path=file.js
Lint Command
Lint code without formatting:
bash
1# Lint all files
2biome lint .
3
4# Fix linting issues
5biome lint --write .
6
7# Show rule names
8biome lint --verbose .
9
10# Apply unsafe fixes
11biome lint --write --unsafe .
Configuration Deep Dive
json
1{
2 "formatter": {
3 "enabled": true,
4 "formatWithErrors": false,
5 "indentStyle": "space",
6 "indentWidth": 2,
7 "lineEnding": "lf",
8 "lineWidth": 80,
9 "attributePosition": "auto"
10 },
11 "javascript": {
12 "formatter": {
13 "quoteStyle": "single",
14 "jsxQuoteStyle": "double",
15 "quoteProperties": "asNeeded",
16 "trailingCommas": "all",
17 "semicolons": "asNeeded",
18 "arrowParentheses": "always",
19 "bracketSpacing": true,
20 "bracketSameLine": false
21 }
22 },
23 "json": {
24 "formatter": {
25 "trailingCommas": "none"
26 }
27 }
28}
Linter Configuration
json
1{
2 "linter": {
3 "enabled": true,
4 "rules": {
5 "recommended": true,
6 "a11y": {
7 "recommended": true,
8 "noAutofocus": "error",
9 "useKeyWithClickEvents": "warn"
10 },
11 "complexity": {
12 "recommended": true,
13 "noForEach": "off",
14 "useLiteralKeys": "error"
15 },
16 "correctness": {
17 "recommended": true,
18 "noUnusedVariables": "error",
19 "useExhaustiveDependencies": "warn"
20 },
21 "performance": {
22 "recommended": true,
23 "noAccumulatingSpread": "warn"
24 },
25 "security": {
26 "recommended": true,
27 "noDangerouslySetInnerHtml": "error"
28 },
29 "style": {
30 "recommended": true,
31 "noNonNullAssertion": "warn",
32 "useConst": "error",
33 "useTemplate": "warn"
34 },
35 "suspicious": {
36 "recommended": true,
37 "noExplicitAny": "warn",
38 "noArrayIndexKey": "error"
39 }
40 }
41 }
42}
File Ignore Patterns
json
1{
2 "files": {
3 "ignore": [
4 "node_modules",
5 "dist",
6 "build",
7 ".next",
8 "coverage",
9 "*.min.js",
10 "public/assets/**"
11 ],
12 "ignoreUnknown": false,
13 "include": ["src/**/*.ts", "src/**/*.tsx"]
14 }
15}
Override Configuration for Specific Files
json
1{
2 "overrides": [
3 {
4 "include": ["**/*.test.ts", "**/*.spec.ts"],
5 "linter": {
6 "rules": {
7 "suspicious": {
8 "noExplicitAny": "off"
9 }
10 }
11 }
12 },
13 {
14 "include": ["scripts/**/*.js"],
15 "formatter": {
16 "lineWidth": 120
17 }
18 }
19 ]
20}
VS Code Integration
1. Install Biome Extension
bash
1# Install from VS Code marketplace
2code --install-extension biomejs.biome
2. VS Code Settings (.vscode/settings.json)
json
1{
2 "[javascript]": {
3 "editor.defaultFormatter": "biomejs.biome",
4 "editor.formatOnSave": true,
5 "editor.codeActionsOnSave": {
6 "quickfix.biome": "explicit",
7 "source.organizeImports.biome": "explicit"
8 }
9 },
10 "[typescript]": {
11 "editor.defaultFormatter": "biomejs.biome",
12 "editor.formatOnSave": true,
13 "editor.codeActionsOnSave": {
14 "quickfix.biome": "explicit",
15 "source.organizeImports.biome": "explicit"
16 }
17 },
18 "[typescriptreact]": {
19 "editor.defaultFormatter": "biomejs.biome",
20 "editor.formatOnSave": true
21 },
22 "[json]": {
23 "editor.defaultFormatter": "biomejs.biome",
24 "editor.formatOnSave": true
25 },
26 "biome.lspBin": "./node_modules/@biomejs/biome/bin/biome"
27}
3. Workspace Settings
json
1{
2 "editor.formatOnSave": true,
3 "editor.formatOnPaste": true,
4 "editor.defaultFormatter": "biomejs.biome",
5 "biome.rename": true,
6 "files.autoSave": "onFocusChange"
7}
Migration from ESLint and Prettier
bash
1# Remove ESLint and Prettier
2npm uninstall eslint prettier eslint-config-prettier \
3 eslint-plugin-react eslint-plugin-import \
4 @typescript-eslint/parser @typescript-eslint/eslint-plugin
5
6# Remove configuration files
7rm .eslintrc.js .eslintrc.json .prettierrc .prettierignore
2. Migrate Configuration
Use Biome's migration tool:
bash
1# Migrate from Prettier config
2biome migrate prettier --write
3
4# Migrate from ESLint config
5biome migrate eslint --write
3. Manual Migration
Prettier → Biome Formatter:
json
1// .prettierrc (old)
2{
3 "semi": false,
4 "singleQuote": true,
5 "trailingComma": "all",
6 "printWidth": 100
7}
8
9// biome.json (new)
10{
11 "formatter": {
12 "lineWidth": 100
13 },
14 "javascript": {
15 "formatter": {
16 "semicolons": "asNeeded",
17 "quoteStyle": "single",
18 "trailingCommas": "all"
19 }
20 }
21}
ESLint → Biome Linter:
json
1// .eslintrc.json (old)
2{
3 "rules": {
4 "no-unused-vars": "error",
5 "prefer-const": "warn"
6 }
7}
8
9// biome.json (new)
10{
11 "linter": {
12 "rules": {
13 "correctness": {
14 "noUnusedVariables": "error"
15 },
16 "style": {
17 "useConst": "warn"
18 }
19 }
20 }
21}
4. Update Scripts
json
1{
2 "scripts": {
3 "lint": "biome lint .",
4 "lint:fix": "biome lint --write .",
5 "format": "biome format --write .",
6 "check": "biome check --write ."
7 }
8}
Git Hooks Integration
Using Husky + lint-staged
bash
1# Install dependencies
2npm install --save-dev husky lint-staged
3npx husky init
.husky/pre-commit:
bash
1#!/usr/bin/env sh
2. "$(dirname -- "$0")/_/husky.sh"
3
4npx lint-staged
package.json:
json
1{
2 "lint-staged": {
3 "*.{js,ts,jsx,tsx,json}": [
4 "biome check --write --no-errors-on-unmatched"
5 ]
6 }
7}
Using Lefthook
lefthook.yml:
yaml
1pre-commit:
2 commands:
3 lint:
4 glob: "*.{js,ts,jsx,tsx,json}"
5 run: biome check --write --no-errors-on-unmatched {staged_files}
Simple Git Hook (no dependencies)
.git/hooks/pre-commit:
bash
1#!/bin/bash
2
3# Get staged files
4STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx|json)$')
5
6if [ -n "$STAGED_FILES" ]; then
7 echo "Running Biome on staged files..."
8 npx @biomejs/biome check --write --no-errors-on-unmatched $STAGED_FILES
9
10 # Add formatted files back to staging
11 git add $STAGED_FILES
12fi
CI/CD Integration
GitHub Actions
yaml
1name: Biome CI
2
3on:
4 push:
5 branches: [main, develop]
6 pull_request:
7 branches: [main]
8
9jobs:
10 biome:
11 runs-on: ubuntu-latest
12 steps:
13 - uses: actions/checkout@v4
14
15 - name: Setup Node.js
16 uses: actions/setup-node@v4
17 with:
18 node-version: '20'
19 cache: 'npm'
20
21 - name: Install dependencies
22 run: npm ci
23
24 - name: Run Biome CI
25 run: npx @biomejs/biome ci .
26
27 - name: Check formatting
28 run: npx @biomejs/biome format .
29
30 - name: Lint
31 run: npx @biomejs/biome lint .
GitLab CI
yaml
1biome:
2 image: node:20-alpine
3 stage: test
4 script:
5 - npm ci
6 - npx @biomejs/biome ci .
7 cache:
8 paths:
9 - node_modules/
10 only:
11 - merge_requests
12 - main
CircleCI
yaml
1version: 2.1
2
3jobs:
4 biome:
5 docker:
6 - image: cimg/node:20.11
7 steps:
8 - checkout
9 - restore_cache:
10 keys:
11 - deps-{{ checksum "package-lock.json" }}
12 - run: npm ci
13 - save_cache:
14 paths:
15 - node_modules
16 key: deps-{{ checksum "package-lock.json" }}
17 - run: npx @biomejs/biome ci .
18
19workflows:
20 test:
21 jobs:
22 - biome
Import Sorting
Biome includes built-in import sorting:
bash
1# Organize imports
2biome check --write --organize-imports-enabled=true .
Configuration:
json
1{
2 "organizeImports": {
3 "enabled": true
4 }
5}
Example:
typescript
1// Before
2import { useState } from 'react';
3import axios from 'axios';
4import { Button } from './components/Button';
5import type { User } from './types';
6import './styles.css';
7
8// After (sorted)
9import type { User } from './types';
10
11import axios from 'axios';
12import { useState } from 'react';
13
14import { Button } from './components/Button';
15
16import './styles.css';
TypeScript Support
Biome has first-class TypeScript support:
json
1{
2 "linter": {
3 "rules": {
4 "suspicious": {
5 "noExplicitAny": "warn",
6 "noUnsafeDeclarationMerging": "error"
7 },
8 "correctness": {
9 "noUnusedVariables": "error"
10 },
11 "style": {
12 "useImportType": "error",
13 "useExportType": "error"
14 }
15 }
16 }
17}
Type-aware linting:
typescript
1// Biome detects unused variables
2const unused = 123; // ❌ Error
3
4// Enforces type imports
5import { User } from './types'; // ❌ Error
6import type { User } from './types'; // ✅ Correct
7
8// Detects unsafe type assertions
9const 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
json
1{
2 "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
3 "extends": [],
4 "formatter": {
5 "enabled": true,
6 "indentStyle": "space",
7 "indentWidth": 2
8 },
9 "linter": {
10 "enabled": true,
11 "rules": {
12 "recommended": true
13 }
14 }
15}
Package Override
json
1{
2 "extends": ["../../biome.json"],
3 "formatter": {
4 "lineWidth": 100
5 },
6 "linter": {
7 "rules": {
8 "style": {
9 "noNonNullAssertion": "off"
10 }
11 }
12 }
13}
Monorepo Scripts
json
1{
2 "scripts": {
3 "check": "biome check .",
4 "check:packages": "biome check packages/*",
5 "format": "biome format --write .",
6 "lint": "biome lint packages/*"
7 }
8}
Speed Comparison
| Tool | Time (10,000 files) |
|---|
| ESLint + Prettier | ~60s |
| Biome | ~0.6s |
100x faster on average workloads.
Caching
Biome includes intelligent caching:
bash
1# First run (no cache)
2biome check . # 1.2s
3
4# Second run (with cache)
5biome check . # 0.1s
6
7# Clear cache
8rm -rf node_modules/.cache/biome
Parallel Processing
Biome uses all CPU cores by default:
bash
1# Limit CPU cores
2biome check --max-diagnostics=50 .
3
4# Verbose output
5biome check --verbose .
Common Patterns
React Projects
json
1{
2 "linter": {
3 "rules": {
4 "a11y": {
5 "recommended": true,
6 "useButtonType": "error",
7 "useKeyWithClickEvents": "error"
8 },
9 "correctness": {
10 "useExhaustiveDependencies": "warn",
11 "useHookAtTopLevel": "error"
12 },
13 "suspicious": {
14 "noArrayIndexKey": "error"
15 }
16 }
17 },
18 "javascript": {
19 "formatter": {
20 "jsxQuoteStyle": "double"
21 }
22 }
23}
Next.js Projects
json
1{
2 "files": {
3 "ignore": [".next", "out", "node_modules"]
4 },
5 "overrides": [
6 {
7 "include": ["app/**/*.tsx", "pages/**/*.tsx"],
8 "linter": {
9 "rules": {
10 "a11y": {
11 "recommended": true
12 }
13 }
14 }
15 }
16 ]
17}
Node.js Backend
json
1{
2 "linter": {
3 "rules": {
4 "security": {
5 "recommended": true,
6 "noGlobalEval": "error"
7 },
8 "correctness": {
9 "noUnusedVariables": "error"
10 }
11 }
12 },
13 "javascript": {
14 "formatter": {
15 "semicolons": "always"
16 }
17 }
18}
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
bash
1# Check if formatter is enabled
2biome rage
3
4# Verify file is not ignored
5biome check --verbose src/file.ts
6
7# Check VS Code extension logs
8# View → Output → Biome
Conflicts with Prettier
bash
1# Disable Prettier in VS Code settings
2"[javascript]": {
3 "editor.defaultFormatter": "biomejs.biome"
4}
5
6# Remove Prettier dependencies
7npm uninstall prettier
bash
1# Check cache location
2biome rage
3
4# Clear cache
5rm -rf node_modules/.cache/biome
6
7# Reduce max diagnostics
8biome check --max-diagnostics=20 .
Rule Configuration Not Working
json
1// Ensure correct category
2{
3 "linter": {
4 "rules": {
5 "correctness": { // Category name matters
6 "noUnusedVariables": "error"
7 }
8 }
9 }
10}
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:
json
1{
2 "lint": "biome check src/ --diagnostic-level=error",
3 "lint:fix": "biome check src/ --write",
4 "format": "biome format src/ --write"
5}
Resources
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