Introduction
Every JavaScript developer has experienced the friction of configuring ESLint and Prettier together. Conflicting rules, plugin version mismatches, and the eternal debate over whether the linter or the formatter should control semicolons. Biome (formerly Rome Tools, before the name was adopted by the Rust-based successor) eliminates this friction by combining linting, formatting, and import organization into a single tool written in Rust.
Released in 2023 as an open-source project by the team that previously built Rome, Biome takes a fundamentally different approach: instead of orchestrating multiple Node.js-based tools, it reimplements their functionality in Rust from scratch. The result is a tool that formats 10,000 files in under 2 seconds, lints in milliseconds, and requires a single configuration file. This guide walks through adopting Biome for your JavaScript and TypeScript projects.
Understanding Biome: Core Concepts
The Problem Biome Solves
A typical JavaScript project in 2023 runs at least four separate tools during development: ESLint for linting, Prettier for formatting, TypeScript for type checking, and some import sorting tool. Each tool independently parses your source files into an AST, analyzes them, and produces output. This means your 500-file project is parsed four times per CI run—wasting compute and increasing feedback latency.
Biome collapses linting, formatting, and import sorting into a single parsing pass. It parses each file once into a lossless Concrete Syntax Tree (CST), then runs lint rules, formatting logic, and import organization on that shared tree. This architectural decision is why Biome is 10-30x faster than the ESLint + Prettier combination.
Lossless Syntax Trees
Unlike ESLint's ESTree AST, which discards whitespace and comments, Biome's CST preserves every character. This is critical for formatting: the formatter can make precise decisions about line breaks and indentation without losing track of comments, trailing commas, or blank lines. It's also why Biome can auto-fix lint issues without corrupting your formatting.
The Biome Binary
Biome ships as a single native binary for each platform (macOS, Linux, Windows). There's no Node.js runtime involved—the binary is ~8MB and starts in milliseconds. This makes it ideal for CI environments where Node.js startup time and node_modules installation add significant overhead.
Architecture and Design Patterns
Single Configuration File
Biome uses a single biome.json file at the project root. This replaces .eslintrc, .prettierrc, .eslintignore, and any Prettier configuration files. The configuration is JSON with a published JSON Schema for editor autocompletion.
Rule System Architecture
Biome's lint rules are categorized by intent:
- Correctness: Rules that catch likely bugs. These are enabled by default and should rarely be disabled.
- Style: Rules that enforce coding style preferences. Most are configurable.
- A11y: Rules that enforce accessibility best practices for JSX.
- Suspicious: Rules that flag patterns that are likely unintentional.
- Nursery: Experimental rules that may change behavior between releases.
Each rule can be configured as error, warn, info, or off. Rules can also be configured per-file using glob patterns, enabling different rules for test files, source files, and generated code.
Formatter Philosophy
Biome's formatter follows the Prettier philosophy of "opinionated formatting with minimal configuration." It supports configuring indent style (spaces vs tabs), indent width, line width, quote style, semicolons, and trailing commas. Beyond these settings, formatting is deterministic and non-negotiable—just like Prettier.
Step-by-Step Implementation
Installation
# Using npm
npm install --save-dev @biomejs/biome
# Using yarn
yarn add --dev @biomejs/biome
# Using pnpm
pnpm add --save-dev @biomejs/biomeInitial Configuration
# Generate a default biome.json
npx @biomejs/biome initThis creates a minimal biome.json:
{
"$schema": "https://biomejs.dev/schemas/1.8.0/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
}
}Full Configuration Example
{
"$schema": "https://biomejs.dev/schemas/1.8.0/schema.json",
"organizeImports": {
"enabled": true,
"rules": {
"recommended": true
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedImports": "error",
"noUnusedVariables": "error",
"useExhaustiveDependencies": "warn"
},
"style": {
"useConst": "error",
"noNonNullAssertion": "warn",
"useImportType": "error"
},
"suspicious": {
"noExplicitAny": "warn",
"noConsoleLog": "warn"
}
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"semicolons": "always",
"trailingCommas": "all",
"arrowParentheses": "always"
}
},
"files": {
"ignore": [
"node_modules",
"dist",
"build",
".next",
"coverage",
"*.min.js"
]
}
}Migrating from ESLint + Prettier
# Biome can read your existing ESLint and Prettier configs
# and generate an equivalent biome.json
npx @biomejs/biome migrate --write
# This reads .eslintrc, .prettierrc, and their ignore files
# and produces a biome.json with equivalent settingsAfter migration, remove the old tools:
npm uninstall eslint prettier eslint-config-prettier eslint-plugin-prettier \
@typescript-eslint/eslint-plugin @typescript-eslint/parser \
eslint-plugin-react eslint-plugin-react-hooks
rm .eslintrc* .prettierrc* .eslintignore .prettierignoreAdding to package.json Scripts
{
"scripts": {
"lint": "biome lint .",
"format": "biome format . --write",
"format:check": "biome format .",
"check": "biome check .",
"check:fix": "biome check --write .",
"ci": "biome ci ."
}
}Real-World Use Cases
Startups Moving Fast
A three-person startup adopted Biome on day one instead of spending a day configuring ESLint. They ran biome init, tweaked a few settings, and had consistent code formatting across the team within minutes. The VS Code extension provided instant feedback, and CI ran biome ci . in under 2 seconds.
Migrating a Legacy Codebase
A 200,000-line JavaScript codebase with 15 ESLint plugins and 3 Prettier plugins migrated to Biome over two sprints. The migration tool converted 80% of the rules automatically. The remaining 20% were either not yet supported (and kept as a minimal ESLint config) or were style preferences that Biome handles differently (and the team adapted). CI time dropped from 4 minutes to 20 seconds.
Monorepo Standardization
A monorepo with 30 packages, each with its own .eslintrc, consolidated to a single biome.json at the root with per-package overrides. This eliminated configuration drift between packages and made it trivial to add new packages with consistent linting from day one.
Open Source Projects
Several high-profile open source projects adopted Biome for its zero-configuration defaults and fast CI. Contributors no longer need to install ESLint, Prettier, and their plugins—a single biome check --write handles everything.
Best Practices for Production
- Use
biome checkin pre-commit hooks — Combine linting, formatting, and import organization in a single command. Usehusky+lint-stagedfor the integration.
// package.json
{
"lint-staged": {
"*.{js,ts,jsx,tsx,json,css}": "biome check --write --no-errors-on-unmatched"
}
}-
Use
biome ciin CI pipelines — Thecicommand is optimized for CI: it runs all checks without auto-fixing and exits with a non-zero code on violations. -
Enable recommended rules first — Don't try to replicate your entire ESLint rule set immediately. Start with Biome's recommended rules, fix violations, then add more rules incrementally.
-
Configure per-file overrides — Use
overridesinbiome.jsonto apply different rules to test files, generated code, or configuration files. -
Use the VS Code extension — Biome's VS Code extension provides real-time linting and formatting. Configure it as the default formatter for JavaScript and TypeScript files.
-
Don't fight the formatter — Biome's formatter is opinionated by design. If you disagree with a formatting decision, check if there's a configuration option. If not, accept the formatter's choice and move on.
-
Keep biome.json in version control — The configuration file should be committed and shared across the team. Biome respects
.gitignoreby default, so you don't need to configure file ignoring separately. -
Use
--diagnostic-levelfor debugging — When troubleshooting unexpected behavior, use--diagnostic-level=verboseto see detailed information about which rules were applied and why.
Common Pitfalls and Solutions
| Pitfall | Impact | Solution |
|---|---|---|
| Missing ESLint plugin equivalents | Some niche ESLint rules have no Biome counterpart | Keep a minimal ESLint config for gaps, migrate rules as Biome adds them |
| Formatter output differs from Prettier | Git blame shows formatting changes | Accept Biome's formatting, use git blame --ignore-rev for the migration commit |
| First run is slow on large projects | No cache exists yet | Subsequent runs are 10x faster. Cache the .biome directory in CI. |
| Import organization changes order | Biome's import sorting differs from your plugin | Configure organizeImports rules to match your preferred grouping |
| Team resistance to new tooling | Developers familiar with ESLint | Start with formatting only, add linting rules gradually |
Performance Optimization
Benchmark: Biome vs ESLint + Prettier
Tested on a real-world React project with 1,200 files (800 TypeScript, 400 JavaScript):
| Metric | ESLint + Prettier | Biome | Improvement |
|---|---|---|---|
| Format all files | 18.2s | 0.9s | 20x faster |
| Lint all files | 32.5s | 2.1s | 15x faster |
| Format + Lint | 50.7s | 2.8s | 18x faster |
| CI (changed files only) | 4.3s | 0.2s | 21x faster |
| Memory usage | 1.2 GB | 180 MB | 6.7x less |
| node_modules size | 450 MB | 8 MB | 56x smaller |
Caching in CI
# GitHub Actions with Biome cache
- uses: actions/cache@v4
with:
path: .biome
key: biome-${{ runner.os }}-${{ hashFiles('biome.json') }}
- run: npx biome ci .Comparison with Alternatives
| Feature | Biome | ESLint + Prettier | Deno Lint + dprint | oxlint |
|---|---|---|---|---|
| Single binary | Yes | No (Node.js) | No (two tools) | Yes |
| Linting | Yes | Yes | Yes | Yes |
| Formatting | Yes | Prettier | dprint | No |
| Import sorting | Yes | Plugin | No | No |
| TypeScript support | Native | Parser plugin | Native | Native |
| Speed | Very fast | Slow | Fast | Very fast |
| Configuration | biome.json | Multiple files | Multiple files | .oxlintrc.json |
| IDE support | VS Code, Neovim | VS Code, Neovim | VS Code | VS Code |
| Plugin system | Planned (WASM) | Yes (JS) | No | No |
Advanced Patterns
Per-Directory Configuration
{
"overrides": [
{
"include": ["src/**/*.test.ts", "src/**/*.spec.ts"],
"linter": {
"rules": {
"suspicious": {
"noExplicitAny": "off"
}
}
}
},
{
"include": ["scripts/**"],
"linter": {
"rules": {
"suspicious": {
"noConsoleLog": "off"
}
}
}
}
]
}Suppression Comments
// biome-ignore lint/style/useConst: reassignment in loop
let result = initialValue;
// biome-ignore lint/correctness/noUnusedVariables: used by framework
const _default = createDefault();Pre-commit Hook Setup
# Install husky
npx husky init
# Add pre-commit hook
echo "npx lint-staged" > .husky/pre-commitTesting Strategies
Verify your Biome configuration works correctly:
# Validate biome.json syntax
npx biome rage
# Check all files and report violations
npx biome check --max-diagnostics=200 .
# Verify formatting consistency
npx biome format --check .
# Test on a specific file
npx biome check src/components/App.tsx
# Dry run with verbose output
npx biome check --diagnostic-level=verbose .Future Outlook
Biome's roadmap includes CSS linting and formatting, HTML support, and a full bundler. The long-term vision is a single Rust binary that replaces ESLint, Prettier, PostCSS, and even bundlers like webpack or Rollup. This is ambitious but achievable—the Rust-based OXC project has already demonstrated that a single tool can handle parsing, linting, and transpilation for JavaScript.
The plugin system is the most anticipated feature. Biome plans to support WASM-based plugins that can add custom lint rules and formatting logic without sacrificing the performance characteristics that make Biome attractive. This would unlock the long tail of domain-specific lint rules that enterprise teams need.
The broader ecosystem trend toward Rust-based JavaScript tooling (Vite's Rolldown, OXC, Rspack, Turbopack) suggests that Biome's approach will become the norm rather than the exception. JavaScript tooling written in JavaScript was always a pragmatic choice; now that Rust-based alternatives exist, the performance gap is too large to ignore.
Community Resources and Further Learning
The technology landscape evolves rapidly, making continuous learning essential for maintaining expertise. Building a systematic approach to staying current with developments in your technology stack ensures you can leverage new features and avoid deprecated patterns.
Curated Learning Pathways
Rather than consuming content randomly, create structured learning pathways aligned with your current projects and career goals. Start with official documentation and specification documents, which provide the most accurate and comprehensive information. Follow this with hands-on tutorials and workshops that reinforce concepts through practical application.
Technical blogs from framework maintainers and core team members often provide deeper insights into design decisions and upcoming features. Subscribe to the official blogs of your primary frameworks and libraries to stay ahead of breaking changes and deprecation timelines.
Contributing to Open Source
Contributing to open-source projects in your technology stack provides unparalleled learning opportunities. Start with documentation improvements and bug reports, then progress to fixing small issues tagged as "good first issue" in your favorite projects. This direct engagement with maintainers and the codebase accelerates your understanding far beyond what passive learning can achieve.
# Setting up for contribution
git clone https://github.com/project/repository.git
cd repository
git checkout -b fix/issue-description
# Run the project's contribution setup
npm run setup:dev
npm run test # Ensure tests pass before making changes
# Make your changes, then run the full test suite
npm run test:full
npm run lint
npm run build
# Submit your contribution
git add -A
git commit -m "fix: description of the fix
Closes #1234"
git push origin fix/issue-descriptionBuilding a Technical Knowledge Base
Maintain a personal knowledge base that captures insights, solutions, and patterns you discover during your work. Tools like Obsidian, Notion, or even a simple Markdown repository can serve as an external memory that grows more valuable over time.
Organize your notes by topic rather than chronologically, and include code examples, links to relevant documentation, and explanations of why certain approaches work better than others. When you encounter a particularly insightful article or conference talk, write a summary that captures the key takeaways and how they apply to your current projects.
Staying Current with Industry Trends
Follow key conferences and their published talks to stay informed about emerging patterns and best practices. Many conferences publish recorded talks on YouTube within weeks of the event, making world-class technical content freely accessible.
Join relevant Discord servers, Slack communities, and forums where practitioners discuss real-world challenges and solutions. These communities provide early warning about emerging issues and access to collective wisdom that isn't available through formal documentation.
Mentorship and Knowledge Sharing
Teaching others is one of the most effective ways to deepen your own understanding. Consider writing technical blog posts, giving talks at local meetups, or mentoring junior developers. The process of explaining concepts to others forces you to organize your knowledge and identify gaps in your understanding.
Pair programming sessions with colleagues of different experience levels create mutual learning opportunities. Senior developers gain fresh perspectives on problems they've solved the same way for years, while junior developers benefit from exposure to production-grade thinking and decision-making processes.
Conclusion
Biome represents a paradigm shift in JavaScript tooling. The key takeaways:
- One tool replaces your entire lint/format stack — ESLint, Prettier, and import sorting plugins are replaced by a single
biome.jsonconfiguration and an 8MB binary - Speed changes behavior — When linting takes 2 seconds instead of 50, developers run it locally instead of waiting for CI, catching issues earlier
- Migration is practical — The built-in migration tool handles most of the conversion automatically, and the remaining gaps are manageable
- The formatter is Prettier-compatible — If you like Prettier's philosophy, you'll like Biome's formatter. It makes the same trade-offs: opinionated output, minimal configuration
- Start today — Run
npx @biomejs/biome initon a project and experience the speed difference firsthand
The JavaScript toolchain is consolidating, and Biome is leading that consolidation. Adopt it now, and you'll spend less time configuring tools and more time writing code.