shared-tooling-biome · diff
git:20260316.063411a to git:20260316.02848e0
100 added, 562 removed. Audit A to A.
---
name: shared-tooling-biome
description: Biome v2 unified linter, formatter, and import organizer — single Rust-powered tool replacing ESLint + Prettier with 97% Prettier compatibility and 20x faster performance
---
# Biome
> **Quick Guide:** Biome is a unified linter, formatter, and import organizer for JavaScript, TypeScript, JSX, TSX, JSON, CSS, and GraphQL. Single Rust binary replaces ESLint + Prettier with 97% Prettier compatibility. Use `biome.json` for all configuration. Run `biome check --write` to lint, format, and organize imports in one pass. Use `biome ci` in pipelines.
>
> **Current stable version:** Biome v2.4.x (March 2026). Biome v2 introduced type-aware linting, nested configs, and a revamped import organizer.
---
<critical_requirements>
## CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST use `biome.json` or `biome.jsonc` for ALL configuration — Biome does not use JavaScript config files)**
**(You MUST pin Biome to an exact version with `--save-exact` — Biome formatting can change between versions)**
**(You MUST use `biome ci` in CI pipelines, NOT `biome check` — `ci` is read-only with no `--write` flag)**
**(You MUST use `biome check --write` for local development — runs linter, formatter, and import organizer in one pass)**
**(You MUST include `$schema` in biome.json for editor autocompletion and validation)**
</critical_requirements>
---
**Auto-detection:** Biome, biome.json, biome.jsonc, @biomejs/biome, biome check, biome lint, biome format, biome ci, biome-ignore, organizeImports, biome migrate
**When to use:**
- Setting up a unified linter + formatter for JavaScript/TypeScript projects
- Replacing ESLint + Prettier with a single, faster tool
- Configuring import organizing with custom group ordering
- Migrating from ESLint and/or Prettier to Biome
- Setting up CI pipelines with `biome ci`
- Configuring pre-commit hooks with Biome's `--staged` flag
**When NOT to use:**
- Projects requiring ESLint plugins with no Biome equivalent (e.g., custom framework-specific plugins)
- Projects needing Markdown, YAML, or TOML formatting (Biome does not support these yet)
- Runtime code (this is build-time tooling only)
- Git hooks setup details (see `shared-tooling-git-hooks` for Husky/Lefthook patterns)
- TypeScript compiler configuration (see `shared-tooling-typescript-config`)
**Key patterns covered:**
- biome.json configuration with formatter, linter, and assist settings
- Linter rule groups (recommended, all, nursery) and severity levels
- Formatter configuration (indent style, line width, quotes, semicolons)
- Import organizer with custom group ordering
- CLI commands: check, format, lint, ci, migrate
- Migration from ESLint + Prettier
- Git hooks integration (Husky, Lefthook, `--staged` flag)
- CI integration with GitHub Actions and GitLab CI
- Editor integration (VS Code, JetBrains)
- Suppression comments (`biome-ignore`, `biome-ignore-all`, range suppressions)
- Nested configuration for monorepos
- Overrides for file-specific settings
- **Detailed resources:**
+ ---
- - For practical examples and migration guides, see [examples/biome.md](examples/biome.md)
- - For CLI quick reference and configuration options, see [reference.md](reference.md)
+ ## Examples
- **Related skills:**
+ - [Setup & Configuration](examples/setup.md) — Installation, biome.json, VS Code, monorepos, framework configs
+ - [Linting Rules](examples/linting.md) — Rule groups, domains, suppressions, overrides, import ordering
+ - [Formatting](examples/formatting.md) — Formatter options, Prettier compatibility, option mapping
+ - [CI & Git Hooks](examples/ci.md) — GitHub Actions, GitLab CI, Husky, Lefthook, staged files
+ - [Migrating from ESLint/Prettier](examples/migration.md) — Automated migration, rule mapping, package cleanup
+ **Other resources:**
+
+ - [CLI Quick Reference](reference.md) — All CLI commands, flags, and configuration option tables
- For ESLint + Prettier configuration (alternative approach), see `shared-tooling-eslint-prettier`
- For git hooks and lint-staged, see `shared-tooling-git-hooks`
- For TypeScript compiler configuration, see `shared-tooling-typescript-config`
- For daily coding conventions (naming, imports, constants), see CLAUDE.md
---
<philosophy>
## Philosophy
Biome unifies linting, formatting, and import organizing into a **single tool with a single configuration file**. Built in Rust, it delivers 20x faster performance than ESLint + Prettier while maintaining 97% Prettier compatibility.
**Core principles:**
1. **One tool, one config** — biome.json replaces .eslintrc, prettier.config, and import sorting plugins
2. **Sensible defaults** — Biome works out of the box with recommended rules enabled; zero-config is a valid setup
3. **Speed as a feature** — Rust-powered binary processes large codebases in milliseconds, not seconds
4. **Unified commands** — `biome check --write` runs everything in one pass (lint + format + organize imports)
5. **Safe by default** — Safe fixes apply automatically; unsafe fixes require explicit `--unsafe` flag
**When to use Biome:**
- Greenfield projects wanting a single, fast tool
- Projects where ESLint + Prettier configuration complexity is a burden
- Large codebases where linting/formatting speed matters
- Teams wanting zero-config or minimal-config setup
- Projects needing JS/TS/JSX/TSX/JSON/CSS/GraphQL support
**When NOT to use Biome:**
- Projects requiring niche ESLint plugins with no Biome equivalent
- Projects needing Markdown, YAML, or TOML formatting
- Projects heavily invested in custom ESLint rules that cannot be replicated
- Teams requiring ESLint's mature plugin ecosystem (accessibility plugins, framework-specific rules)
</philosophy>
---
<patterns>
## Core Patterns
### Pattern 1: Basic biome.json Configuration
Every Biome project starts with a `biome.json` at the project root. Use `biome init` to scaffold one, then customize.
- #### Initialization
-
```bash
# Install Biome (always pin exact version)
npm install --save-dev --save-exact @biomejs/biome
# Create default biome.json
npx @biomejs/biome init
```
- #### Standard Configuration
-
```jsonc
- // biome.json
+ // biome.json — minimal recommended setup
{
"$schema": "https://biomejs.dev/schemas/2.4.7/schema.json",
- "vcs": {
- "enabled": true,
- "clientKind": "git",
- "useIgnoreFile": true,
- },
- "formatter": {
- "enabled": true,
- "indentStyle": "space",
- "indentWidth": 2,
- "lineWidth": 100,
- "lineEnding": "lf",
- },
- "linter": {
- "enabled": true,
- "rules": {
- "recommended": true,
- },
- },
+ "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
+ "formatter": { "indentStyle": "space", "indentWidth": 2, "lineWidth": 100 },
+ "linter": { "rules": { "recommended": true } },
"assist": {
"enabled": true,
- "actions": {
- "source": {
- "organizeImports": "on",
- },
- },
- },
- "javascript": {
- "formatter": {
- "quoteStyle": "double",
- "semicolons": "always",
- "trailingCommas": "all",
- "arrowParentheses": "always",
- "bracketSameLine": false,
- },
- },
- "json": {
- "formatter": {
- "trailingCommas": "none",
- },
+ "actions": { "source": { "organizeImports": "on" } },
},
}
```
- **Why good:** `$schema` enables editor autocompletion and validation, VCS integration respects `.gitignore`, explicit formatter settings match team preferences, recommended linter rules provide a strong baseline, import organizer enabled via assist, language-specific overrides keep JSON strict while JS uses trailing commas
+ **Why good:** `$schema` enables editor autocompletion, VCS integration respects `.gitignore`, explicit `indentStyle: "space"` avoids Biome's tab default, recommended rules provide a strong baseline
```jsonc
- // BAD: No schema, no VCS, relying on Biome defaults that differ from Prettier
- {
- "linter": {
- "enabled": true,
- },
- }
+ // BAD: No schema, no VCS, relying on defaults that differ from Prettier
+ { "linter": { "enabled": true } }
```
- **Why bad:** Missing `$schema` loses editor autocompletion, no VCS integration means linting/formatting node_modules or dist, Biome defaults to tabs (not spaces) which may surprise teams migrating from Prettier, no explicit formatter config leads to unexpected formatting differences
+ **Why bad:** Missing `$schema` loses autocompletion, no VCS means linting node_modules, Biome defaults to tabs which surprises Prettier migrants
+ > **Full example:** See [examples/setup.md](examples/setup.md) for a production-ready biome.json with overrides, framework configs, and monorepo setup.
+
---
### Pattern 2: Linter Rules Configuration
- Biome provides 459+ rules across 8 groups. Rules default to `recommended` which is a curated subset of safe, stable rules.
+ Biome provides 459+ rules across 8 groups. Rules default to `recommended` — a curated subset of safe, stable rules.
#### Rule Groups
| Group | Purpose | Default |
| --------------- | ------------------------------------ | ------------------ |
| `accessibility` | Prevents a11y problems | recommended |
| `complexity` | Simplifies overly complex code | recommended |
| `correctness` | Detects guaranteed errors | recommended |
| `nursery` | Experimental rules (opt-in required) | off |
| `performance` | Catches inefficient patterns | recommended |
| `security` | Identifies security flaws | recommended |
| `style` | Enforces consistent code style | recommended (warn) |
| `suspicious` | Flags likely incorrect patterns | recommended |
#### Severity Levels
| Level | Behavior |
| --------- | ---------------------------------- |
| `"off"` | Rule disabled |
| `"on"` | Default severity for that rule |
| `"info"` | Informational, no CLI exit impact |
| `"warn"` | Non-blocking diagnostic |
| `"error"` | Blocks CLI with non-zero exit code |
- #### Configuring Rules
-
- ```jsonc
- // biome.json
- {
- "linter": {
- "enabled": true,
- "rules": {
- "recommended": true,
- // Enable all style rules (not just recommended)
- "style": {
- "all": true,
- },
- // Disable specific rules
- "complexity": {
- "noForEach": "off",
- },
- // Configure rule with options
- "style": {
- "useNamingConvention": {
- "level": "warn",
- "options": {
- "strictCase": false,
- },
- },
- },
- // Enable nursery rules explicitly
- "nursery": {
- "noConsole": "warn",
- },
- },
- },
- }
- ```
-
- **Why good:** `recommended: true` provides a strong baseline without per-rule config, group-level overrides (`"all": true`) enable entire categories, individual rules can be tuned with options, nursery rules opted into explicitly for experimental features
-
#### Domains (Technology-Specific Rules)
- Biome v2 introduces domains that group rules by technology:
+ Biome v2 introduces domains that group rules by technology. Domains auto-detect from `package.json` dependencies.
```jsonc
- {
- "linter": {
- "domains": {
- "react": "recommended",
- "test": "recommended",
- "solid": "off",
- },
- },
- }
+ { "linter": { "domains": { "react": "recommended", "test": "recommended" } } }
```
- Domains auto-detect from `package.json` dependencies when not explicitly configured.
+ > **Full examples:** See [examples/linting.md](examples/linting.md) for rule configuration, suppressions, overrides, and import ordering.
---
### Pattern 3: Formatter Configuration
- Biome's formatter achieves 97% Prettier compatibility. Global settings apply to all languages; language-specific settings override globals.
-
- #### Global vs Language-Specific Settings
+ Biome's formatter achieves 97% Prettier compatibility. Global settings apply to all languages; language-specific settings override globals. **Biome defaults to tabs** — set `indentStyle: "space"` explicitly when migrating from Prettier.
```jsonc
{
- // Global formatter settings (all languages)
- "formatter": {
- "indentStyle": "space",
- "indentWidth": 2,
- "lineWidth": 100,
- "lineEnding": "lf",
- "bracketSpacing": true,
- },
- // JavaScript/TypeScript-specific overrides
+ "formatter": { "indentStyle": "space", "indentWidth": 2, "lineWidth": 100 },
"javascript": {
- "formatter": {
- "quoteStyle": "double",
- "jsxQuoteStyle": "double",
- "semicolons": "always",
- "trailingCommas": "all",
- "arrowParentheses": "always",
- "bracketSameLine": false,
- },
- },
- // JSON-specific settings
- "json": {
- "formatter": {
- "trailingCommas": "none",
- },
- },
- // CSS formatting (disabled by default, opt-in)
- "css": {
- "formatter": {
- "enabled": true,
- },
+ "formatter": { "quoteStyle": "double", "semicolons": "always" },
},
+ "json": { "formatter": { "trailingCommas": "none" } },
+ "css": { "formatter": { "enabled": true } },
}
```
- **Why good:** Global settings provide a baseline for all languages, language-specific settings override without repetition, CSS/GraphQL formatting explicitly opted into since they are disabled by default
-
- #### Key Differences from Prettier Defaults
-
- | Setting | Biome Default | Prettier Default | Notes |
- | ---------------- | ------------- | ---------------- | ---------------------- |
- | `indentStyle` | `"tab"` | spaces | Biome defaults to tabs |
- | `indentWidth` | `2` | `2` | Same |
- | `lineWidth` | `80` | `80` | Same |
- | `quoteStyle` | `"double"` | `"double"` | Same |
- | `semicolons` | `"always"` | `true` | Different naming |
- | `trailingCommas` | `"all"` | `"all"` | Same (Prettier 3.0+) |
-
- **Important:** When migrating from Prettier, explicitly set `indentStyle: "space"` if your project uses spaces — Biome defaults to tabs.
+ > **Full reference:** See [examples/formatting.md](examples/formatting.md) for all options, Prettier mapping, and language-specific settings.
---
### Pattern 4: Import Organizer
- Biome v2 revamped the import organizer with custom group ordering, export organizing, and import merging.
-
- #### Default Sorting Order
-
- Imports are sorted by "distance" from the current module:
-
- 1. URLs (`https://`, `http://`)
- 2. Packages with protocols (`node:`, `bun:`, `jsr:`, `npm:`)
- 3. Regular packages (`@scoped/lib`, `lib`)
- 4. Aliases (`@/`, `#`, `~`, `$`, `%`)
- 5. Relative/absolute paths
-
- #### Enabling the Organizer
-
- ```jsonc
- {
- "assist": {
- "enabled": true,
- "actions": {
- "source": {
- "organizeImports": "on",
- },
- },
- },
- }
- ```
-
- #### Custom Group Ordering
+ Biome v2 revamped the import organizer with custom group ordering. Configure under `assist.actions.source.organizeImports`.
```jsonc
{
"assist": {
"actions": {
"source": {
"organizeImports": {
"level": "on",
"options": {
"groups": [
":NODE:",
":PACKAGE:",
":BLANK_LINE:",
["@company/**"],
":BLANK_LINE:",
":ALIAS:",
{ "type": true },
],
},
},
},
},
},
}
```
- **Why good:** Predefined groups (`:NODE:`, `:PACKAGE:`, `:ALIAS:`) handle common patterns, `:BLANK_LINE:` creates visual separation between groups, custom glob patterns group company packages together, `{ "type": true }` separates type-only imports
-
#### Predefined Groups
| Group | Matches |
| -------------- | ------------------------------------------ |
| `:NODE:` | Node.js built-ins and `node:` protocol |
| `:PACKAGE:` | Regular npm packages |
| `:ALIAS:` | Aliased imports (`@/`, `#`, `~`, `$`, `%`) |
| `:URL:` | HTTP/HTTPS imports |
| `:BUN:` | Bun-specific modules |
| `:BLANK_LINE:` | Visual separator between groups |
+ > **Full examples:** See [examples/linting.md](examples/linting.md#custom-import-ordering) for import ordering with results.
+
---
### Pattern 5: CLI Commands
- Biome provides focused commands for different workflows. Use `check` locally, `ci` in pipelines.
-
- #### Primary Commands
-
- ```bash
- # Run everything: lint + format + organize imports (read-only)
- npx biome check .
-
- # Run everything with auto-fix
- npx biome check --write .
-
- # Format only
- npx biome format --write .
-
- # Lint only
- npx biome lint --write .
-
- # CI mode (read-only, optimized for pipelines)
- npx biome ci .
- ```
-
- #### Filtering and Targeting
-
- ```bash
- # Run only specific rule groups
- npx biome lint --only=correctness .
-
- # Skip specific rules
- npx biome lint --skip=style/useNamingConvention .
-
- # Check only staged files (pre-commit hooks)
- npx biome check --staged --write .
-
- # Check only changed files (compared to main branch)
- npx biome check --changed --since=main .
-
- # Apply unsafe fixes (requires review)
- npx biome check --write --unsafe .
- ```
-
- #### Output and Reporting
+ Use `check` locally, `ci` in pipelines. Key commands:
```bash
- # Verbose output
- npx biome check --verbose .
-
- # JSON reporter
- npx biome ci --reporter=json .
-
- # GitHub annotations (auto-detected in GitHub Actions)
- npx biome ci --reporter=github .
-
- # GitLab code quality report
- npx biome ci --reporter=gitlab --colors=off > code-quality.json
-
- # Error on warnings (strict mode)
- npx biome ci --error-on-warnings .
-
- # Limit diagnostics output
- npx biome check --max-diagnostics=50 .
+ npx biome check --write . # Lint + format + organize imports (auto-fix)
+ npx biome ci . # CI mode (read-only, optimized for pipelines)
+ npx biome check --staged --write . # Pre-commit hooks (only staged files)
+ npx biome check --changed --since=main . # Changed files only
```
- **Why good:** `check --write` handles everything in one command, `ci` is purpose-built for pipelines (no `--write` flag, better runner integration), `--staged` eliminates the need for lint-staged, `--changed` enables incremental CI checks
+ > **Full reference:** See [examples/ci.md](examples/ci.md) for complete CLI usage, filtering, and reporting options.
---
### Pattern 6: Suppression Comments
- Biome uses `biome-ignore` comments with required explanations for suppressing diagnostics.
-
- #### Inline Suppression (Next Line)
+ Biome uses `biome-ignore` comments with required explanations.
```typescript
// biome-ignore lint/suspicious/noDebugger: needed for local debugging
debugger;
- // biome-ignore lint/complexity/noForEach: readability preference
- items.forEach((item) => process(item));
-
- // biome-ignore format: complex ternary reads better manually formatted
- const value = condition ? longExpressionA : longExpressionB;
- ```
-
- #### File-Level Suppression (Top of File)
-
- ```typescript
- // biome-ignore-all lint/style/noDefaultExport: framework requires default export
- // biome-ignore-all lint/suspicious/noExplicitAny: legacy module without types
-
- export default function Page() {
- // ...
- }
- ```
-
- #### Range Suppression
+ // biome-ignore-all lint/style/noDefaultExport: framework requires default export (top of file only)
- ```typescript
- // biome-ignore-start lint/suspicious/noDoubleEquals: legacy comparison section
- if (a == null) {
- /* ... */
- }
- if (b == undefined) {
- /* ... */
- }
- // biome-ignore-end lint/suspicious/noDoubleEquals: legacy comparison section
+ // biome-ignore-start lint/suspicious/noDoubleEquals: legacy section
+ // biome-ignore-end lint/suspicious/noDoubleEquals: legacy section
```
- #### Suppression Levels
-
- | Level | Example | Scope |
- | -------- | ------------------------------------------ | -------------------- |
- | Category | `biome-ignore lint:` | All lint rules |
- | Group | `biome-ignore lint/suspicious:` | All suspicious rules |
- | Rule | `biome-ignore lint/suspicious/noDebugger:` | Single rule |
+ | Type | Syntax | Scope |
+ | ----------- | -------------------------------------- | ---------------------------- |
+ | Inline | `// biome-ignore <spec>: reason` | Next line |
+ | File-wide | `// biome-ignore-all <spec>: reason` | Entire file (must be at top) |
+ | Range start | `// biome-ignore-start <spec>: reason` | Until matching end |
+ | Range end | `// biome-ignore-end <spec>: reason` | Ends matching range |
- **Important:** Explanations are mandatory. `// biome-ignore lint:` without a reason after the colon will be flagged.
+ > **Full examples:** See [examples/linting.md](examples/linting.md#suppression-comments) for inline, file-level, and range suppressions.
---
### Pattern 7: Nested Configuration (Monorepos)
- Biome v2 supports nested `biome.json` files for monorepo setups. Each subdirectory can override the root config.
-
- #### Root Configuration
+ Biome v2 supports nested `biome.json` files. Each subdirectory can override the root config.
```jsonc
- // biome.json (project root)
- {
- "$schema": "https://biomejs.dev/schemas/2.4.7/schema.json",
- "formatter": {
- "indentStyle": "space",
- "indentWidth": 2,
- "lineWidth": 100,
- },
- "linter": {
- "rules": {
- "recommended": true,
- },
- },
- }
+ // packages/my-app/biome.json — inherits from root
+ { "$schema": "https://biomejs.dev/schemas/2.4.7/schema.json", "extends": "//" }
```
- #### Package-Level Override
-
```jsonc
- // packages/legacy-app/biome.json
+ // packages/legacy-lib/biome.json — relaxes rules
{
"$schema": "https://biomejs.dev/schemas/2.4.7/schema.json",
"root": false,
- "linter": {
- "rules": {
- "suspicious": {
- "noExplicitAny": "off",
- },
- },
- },
+ "linter": { "rules": { "suspicious": { "noExplicitAny": "off" } } },
}
```
- #### Shorthand Extend Syntax
-
- ```jsonc
- // packages/my-app/biome.json
- {
- "$schema": "https://biomejs.dev/schemas/2.4.7/schema.json",
- "extends": "//",
- }
- ```
+ **Why good:** `"extends": "//"` shorthand inherits root config, `"root": false` marks as child, each package can relax or tighten rules independently
- **Why good:** `"root": false` explicitly marks as child config that inherits from parent, `"extends": "//"` is a shorthand for both setting `root: false` and extending the root config, each package can relax or tighten rules without affecting others
+ > **Full examples:** See [examples/setup.md](examples/setup.md#monorepo-nested-configuration) for root + child config patterns.
---
### Pattern 8: Overrides (File-Specific Rules)
Use `overrides` for file-pattern-specific configuration without nested config files.
```jsonc
{
- "linter": {
- "rules": {
- "recommended": true,
- },
- },
"overrides": [
{
- // Relax rules for test files
- "includes": ["**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts"],
- "linter": {
- "rules": {
- "suspicious": {
- "noExplicitAny": "off",
- },
- },
- },
+ "includes": ["**/*.test.ts", "**/*.test.tsx"],
+ "linter": { "rules": { "suspicious": { "noExplicitAny": "off" } } },
},
{
- // Allow default exports for Next.js pages/layouts
"includes": ["**/app/**/page.tsx", "**/app/**/layout.tsx"],
- "linter": {
- "rules": {
- "style": {
- "noDefaultExport": "off",
- },
- },
- },
- },
- {
- // Different formatting for config files
- "includes": ["*.config.ts", "*.config.mjs"],
- "formatter": {
- "lineWidth": 120,
- },
+ "linter": { "rules": { "style": { "noDefaultExport": "off" } } },
},
],
}
```
- **Why good:** Overrides eliminate the need for suppression comments in every file, test files get relaxed rules without compromising production code, framework conventions (default exports in Next.js) handled declaratively
+ **Why good:** Overrides eliminate suppression comments in every file, test files get relaxed rules, framework conventions handled declaratively
+ > **Full examples:** See [examples/linting.md](examples/linting.md#overrides-file-specific-rules) for test, config, and generated file overrides.
+
</patterns>
---
<performance>
## Performance
Biome is written in Rust and processes files in parallel, making it significantly faster than JavaScript-based alternatives.
- ### Benchmark Comparison
-
| Tool | Format Time (1000 files) | Lint Time (1000 files) |
| ----------------- | ------------------------ | ---------------------- |
| Biome | ~100ms | ~200ms |
| Prettier | ~2000ms | N/A |
| ESLint | N/A | ~3000ms |
| ESLint + Prettier | ~5000ms | ~5000ms |
_Approximate benchmarks. Actual performance varies by project size and rule configuration._
- ### Performance Tips
+ **Performance Tips:**
- **Use `biome check`** instead of running `biome format` and `biome lint` separately — single pass is faster
- **Enable VCS integration** to automatically skip ignored files (`.gitignore`)
- **Use `--staged` or `--changed`** in hooks and CI to process only affected files
- **Be selective with nursery rules** — some experimental rules may impact performance
- **Use `--profile-rules`** (v2.4+) to identify slow lint rules in your configuration
- ### Type-Aware Linting Performance
+ **Type-Aware Linting Performance:**
- Biome v2 introduced type-aware linting without the TypeScript compiler. Rules in the `project` and `types` domains trigger file scanning:
+ Biome v2 introduced type-aware linting without the TypeScript compiler. Enable selectively:
- **Default scan** discovers nested configs only (fast)
- **Project domain scan** indexes the full module graph (slower, but still faster than tsc)
- **Types domain scan** adds type inference (most comprehensive, most expensive)
- Enable selectively based on your needs — not all projects need type-aware rules.
-
</performance>
---
<decision_framework>
## Decision Framework
### Biome vs ESLint + Prettier
```
Need linting and formatting?
- ├─ Greenfield project?
- │ ├─ Want simplest possible setup?
- │ │ └─ YES -> Biome (one tool, one config, zero-config works)
- │ ├─ Need niche ESLint plugins?
- │ │ └─ YES -> ESLint + Prettier
- │ └─ Speed is important?
- │ └─ YES -> Biome (20x faster)
- ├─ Existing ESLint + Prettier project?
- │ ├─ Happy with current setup?
- │ │ └─ YES -> Stay with ESLint + Prettier
- │ ├─ Config complexity is a pain?
- │ │ └─ YES -> Migrate to Biome
- │ ├─ Need ESLint plugins without Biome equivalents?
- │ │ └─ YES -> Stay with ESLint + Prettier
- │ └─ Want faster CI/pre-commit hooks?
- │ └─ YES -> Biome (or hybrid: Biome format + ESLint lint)
- └─ Monorepo?
- ├─ Need per-package lint configs?
- │ └─ YES -> Biome v2 nested configs or ESLint 10
- └─ Speed bottleneck in CI?
- └─ YES -> Biome
+ |-- Greenfield project?
+ | |-- Want simplest possible setup? -> Biome (one tool, one config)
+ | |-- Need niche ESLint plugins? -> ESLint + Prettier
+ | +-- Speed is important? -> Biome (20x faster)
+ |-- Existing ESLint + Prettier project?
+ | |-- Happy with current setup? -> Stay with ESLint + Prettier
+ | |-- Config complexity is a pain? -> Migrate to Biome
+ | |-- Need ESLint plugins without Biome equivalents? -> Stay
+ | +-- Want faster CI/pre-commit hooks? -> Biome (or hybrid)
+ +-- Monorepo?
+ |-- Need per-package lint configs? -> Biome v2 nested configs or ESLint 10
+ +-- Speed bottleneck in CI? -> Biome
```
- ### Biome Configuration Complexity
+ ### Configuration Complexity
```
How to configure Biome?
- ├─ Just starting out?
- │ └─ Run `biome init` -> use defaults with `recommended: true`
- ├─ Migrating from ESLint?
- │ └─ Run `biome migrate eslint --write`
- ├─ Migrating from Prettier?
- │ └─ Run `biome migrate prettier --write`
- ├─ Need per-file rules?
- │ ├─ Different rules for test files?
- │ │ └─ Use `overrides` in biome.json
- │ └─ Different rules per package?
- │ └─ Use nested biome.json with `"root": false`
- └─ Need custom import ordering?
- └─ Configure `organizeImports.options.groups`
+ |-- Just starting out? -> Run `biome init`, use defaults with recommended: true
+ |-- Migrating from ESLint? -> Run `biome migrate eslint --write`
+ |-- Migrating from Prettier? -> Run `biome migrate prettier --write`
+ |-- Need per-file rules?
+ | |-- Different rules for test files? -> Use `overrides` in biome.json
+ | +-- Different rules per package? -> Use nested biome.json with "root": false
+ +-- Need custom import ordering? -> Configure organizeImports.options.groups
```
- ### Full Migration vs Hybrid Approach
-
- ```
- Migrating from ESLint + Prettier?
- ├─ Standard rules only (recommended + typescript-eslint)?
- │ └─ Full migration to Biome (Biome covers these)
- ├─ Using framework-specific ESLint plugins?
- │ ├─ React/JSX-a11y/Unicorn?
- │ │ └─ Full migration (Biome has equivalent rules)
- │ ├─ Custom/niche plugins?
- │ │ └─ Hybrid: Biome format + ESLint for custom rules
- │ └─ Many custom rules with specific options?
- │ └─ Hybrid approach (migrate incrementally)
- └─ Just want faster formatting?
- └─ Replace Prettier with Biome format, keep ESLint
- ```
+ > **Full migration decision tree:** See [examples/migration.md](examples/migration.md#full-migration-vs-hybrid-approach).
</decision_framework>
---
<integration>
## Integration Guide
- ### Editor Integration
-
- #### VS Code
-
- Install the [Biome extension](https://marketplace.visualstudio.com/items?itemName=biomejs.biome) from the VS Code Marketplace.
-
- ```jsonc
- // .vscode/settings.json
- {
- // Set Biome as default formatter
- "editor.defaultFormatter": "biomejs.biome",
- // Format on save
- "editor.formatOnSave": true,
- // Organize imports on save
- "editor.codeActionsOnSave": {
- "source.organizeImports.biome": "explicit",
- },
- // Language-specific overrides (if needed)
- "[javascript]": {
- "editor.defaultFormatter": "biomejs.biome",
- },
- "[typescript]": {
- "editor.defaultFormatter": "biomejs.biome",
- },
- "[json]": {
- "editor.defaultFormatter": "biomejs.biome",
- },
- }
- ```
-
- **VS Code Extension v3 features:**
-
- - Multi-root workspace support (each folder runs its own Biome instance)
- - Single-file mode for files outside projects
- - Automatic `biome.json` discovery
-
- #### JetBrains (IntelliJ, WebStorm)
-
- Install the [Biome plugin](https://plugins.jetbrains.com/plugin/22761-biome) from the JetBrains Marketplace.
-
- The plugin auto-discovers Biome from `node_modules/.bin/biome`. Add Biome as a project dependency to ensure the plugin and CLI use the same version.
-
- ### Git Hooks Integration
-
- #### Option A: Husky (No lint-staged Needed)
-
- Biome's `--staged` flag eliminates the need for lint-staged:
-
- ```bash
- # .husky/pre-commit
- npx biome check --write --staged --files-ignore-unknown=true --no-errors-on-unmatched
- ```
-
- #### Option B: Husky + lint-staged
-
- If using lint-staged for multiple tools:
-
- ```jsonc
- // package.json
- {
- "lint-staged": {
- "*.{js,ts,jsx,tsx,json,jsonc,css}": [
- "biome check --write --no-errors-on-unmatched",
- ],
- },
- }
- ```
-
- #### Option C: Lefthook
-
- ```yaml
- # lefthook.yml
- pre-commit:
- commands:
- biome:
- glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}"
- run: npx @biomejs/biome check --write --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files}
- stage_fixed: true
- ```
-
- #### Option D: pre-commit Framework
-
- ```yaml
- # .pre-commit-config.yaml
- repos:
- - repo: https://github.com/biomejs/pre-commit
- rev: "v2.0.6"
- hooks:
- - id: biome-check
- additional_dependencies: ["@biomejs/biome@2.4.7"]
- ```
-
- ### CI Integration
-
- #### GitHub Actions
-
- ```yaml
- # .github/workflows/lint.yml
- name: Lint & Format
- on:
- push:
- branches: [main]
- pull_request:
- branches: [main]
-
- jobs:
- biome:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: biomejs/setup-biome@v2
- with:
- version: latest
- - run: biome ci .
- ```
-
- **Key:** The `biomejs/setup-biome` action installs the Biome binary directly — no Node.js or npm required.
-
- #### GitLab CI
-
- ```yaml
- # .gitlab-ci.yml
- lint:
- image:
- name: ghcr.io/biomejs/biome:latest
- entrypoint: [""]
- script:
- - biome ci --reporter=gitlab --colors=off > /tmp/code-quality.json
- artifacts:
- reports:
- codequality:
- - code-quality.json
- ```
-
- ### Package.json Scripts
-
- ```jsonc
- // package.json
- {
- "scripts": {
- "check": "biome check .",
- "check:fix": "biome check --write .",
- "format": "biome format --write .",
- "lint": "biome lint .",
- "lint:fix": "biome lint --write .",
- "ci": "biome ci .",
- },
- }
- ```
-
**Works with:**
- **React/Next.js/Remix**: Full JSX/TSX support, domain-specific rules for React
- **TypeScript**: Type-aware linting without tsc dependency (Biome v2+)
- **CSS**: Linting enabled by default, formatting opt-in
- **JSON/JSONC**: Full support including tsconfig.json, package.json
- **GraphQL**: Linting enabled by default, formatting opt-in
- **Vue/Svelte/Astro**: Experimental support via `html.experimentalFullSupportEnabled` (v2.4+)
**Replaces / Conflicts with:**
- **ESLint**: Biome replaces ESLint for linting (or use hybrid approach)
- **Prettier**: Biome replaces Prettier for formatting
- **eslint-plugin-import**: Biome's import organizer replaces import sorting plugins
- **eslint-config-prettier**: Not needed — Biome has no formatter/linter conflicts
+ > **CI/editor integration:** See [examples/ci.md](examples/ci.md) and [examples/setup.md](examples/setup.md#vs-code-integration).
+
</integration>
---
<red_flags>
## RED FLAGS
**High Priority Issues:**
- - ❌ Using `biome check` in CI instead of `biome ci` (`check` allows `--write` which is dangerous in pipelines; `ci` is read-only)
- - ❌ Not pinning Biome version with `--save-exact` (formatting can change between minor versions, causing diff noise)
- - ❌ Missing `$schema` in biome.json (loses editor autocompletion, validation, and discoverability)
- - ❌ Using JavaScript config files instead of biome.json (Biome only supports JSON/JSONC configuration)
- - ❌ Running `biome format` and `biome lint` separately when `biome check` does both (wastes time, parses files twice)
+ - Using `biome check` in CI instead of `biome ci` (`check` allows `--write` which is dangerous in pipelines; `ci` is read-only)
+ - Not pinning Biome version with `--save-exact` (formatting can change between minor versions, causing diff noise)
+ - Missing `$schema` in biome.json (loses editor autocompletion, validation, and discoverability)
+ - Using JavaScript config files instead of biome.json (Biome only supports JSON/JSONC configuration)
+ - Running `biome format` and `biome lint` separately when `biome check` does both (wastes time, parses files twice)
**Medium Priority Issues:**
- - ⚠️ Forgetting to set `indentStyle: "space"` when migrating from Prettier (Biome defaults to tabs)
- - ⚠️ Not enabling VCS integration (without it, Biome may process node_modules and dist)
- - ⚠️ Using `--unsafe` without reviewing changes (unsafe fixes can alter program behavior)
- - ⚠️ Not including `--no-errors-on-unmatched` in git hooks (causes failures when no matching files are staged)
- - ⚠️ Enabling all nursery rules (they are experimental and may have bugs or performance issues)
+ - Forgetting to set `indentStyle: "space"` when migrating from Prettier (Biome defaults to tabs)
+ - Not enabling VCS integration (without it, Biome may process node_modules and dist)
+ - Using `--unsafe` without reviewing changes (unsafe fixes can alter program behavior)
+ - Not including `--no-errors-on-unmatched` in git hooks (causes failures when no matching files are staged)
+ - Enabling all nursery rules (they are experimental and may have bugs or performance issues)
**Common Mistakes:**
- Using `"root": true` in a nested config (this is the default; use `"root": false` for child configs)
- Expecting Markdown/YAML formatting support (Biome does not support these languages yet)
- Not running `biome migrate --write` when upgrading major versions (config schema changes between v1 and v2)
- Suppression comments without explanations (`biome-ignore lint:` requires text after the colon)
**Gotchas & Edge Cases:**
- Biome defaults to tabs, not spaces — always set `indentStyle` explicitly when migrating from Prettier
- CSS and GraphQL formatting is disabled by default — must opt in with `"formatter": { "enabled": true }`
- `biome-ignore-all` must be at the top of the file — placing it mid-file triggers an unused suppression warning
- Import organizer is part of `assist`, not `linter` — configure under `assist.actions.source.organizeImports`
- The `--staged` flag makes lint-staged unnecessary for Biome-only setups (since Biome v1.7.0+)
- Type-aware linting (project/types domains) triggers file scanning which can slow down first runs on large projects
- `biome migrate eslint --write` does not migrate inspired rules by default — use `--include-inspired` to include them
- Range suppressions (`biome-ignore-start`/`biome-ignore-end`) must have matching rule specifiers
- Biome treats all JS/TS/JSX/TSX under the `javascript` config key — there is no separate `typescript` section
- Configuration files named `.biome.json` (with leading dot) are also discovered (v2.4+)
</red_flags>
---
<critical_reminders>
## CRITICAL REMINDERS
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST use `biome.json` or `biome.jsonc` for ALL configuration — Biome does not use JavaScript config files)**
**(You MUST pin Biome to an exact version with `--save-exact` — Biome formatting can change between versions)**
**(You MUST use `biome ci` in CI pipelines, NOT `biome check` — `ci` is read-only with no `--write` flag)**
**(You MUST use `biome check --write` for local development — runs linter, formatter, and import organizer in one pass)**
**(You MUST include `$schema` in biome.json for editor autocompletion and validation)**
**Failure to follow these rules will cause inconsistent formatting, broken CI pipelines, and missed lint errors.**
</critical_reminders>