Biome — The Rust Toolchain Replacing ESLint + Prettier, 50x Faster
Posted on: 4/26/2026 8:16:03 AM
Table of contents
- 1. What Is Biome?
- 2. Biome vs ESLint + Prettier — Detailed Comparison
- 3. Installing and Configuring Biome
- 4. Biome's Internal Architecture
- 5. New Features in Biome v2.x (2026)
- 6. Migrating from ESLint + Prettier to Biome
- 7. CI/CD and IDE Integration
- 8. Biome with Vue.js Projects
- 9. Real-World Monorepo Benchmarks
- 10. Conclusion
- References
Are you using ESLint + Prettier and watching your CI lint step take 30-45 seconds? Config files scattered everywhere — .eslintrc.js, .prettierrc, .eslintignore, .prettierignore — and they occasionally conflict with each other? Biome is the answer: a single toolchain written in Rust that lints and formats, 25-50x faster than the traditional ESLint + Prettier combo.
1. What Is Biome?
Biome is a unified toolchain for web projects, written entirely in Rust. It combines a formatter (replacing Prettier) and linter (replacing ESLint) into a single tool, with a single configuration file biome.json. Biome supports JavaScript, TypeScript, JSX, TSX, JSON, CSS, and GraphQL.
Why Rust Changes the Game
ESLint and Prettier are written in JavaScript — running on V8 single-threaded. Biome is written in Rust with parallel parsing, multi-threaded processing, and a zero-copy memory model. The result: linting a 10,000-line monorepo in ~200ms instead of 3-5 seconds.
2. Biome vs ESLint + Prettier — Detailed Comparison
| Criteria | Biome | ESLint + Prettier |
|---|---|---|
| Written in | Rust | JavaScript |
| Lint speed (10k files) | ~0.8 seconds | ~45 seconds |
| Format speed (10k files) | ~0.3 seconds | ~12 seconds |
| Config files | 1 file (biome.json) | 4+ files (.eslintrc, .prettierrc, ignore files...) |
| Format/lint conflicts | Never (same tool) | Frequent (needs eslint-config-prettier) |
| Type-aware linting | Yes (v2.0+) | Yes (typescript-eslint) |
| Plugin system | GritQL plugins (v2.0+) | JavaScript plugins (large ecosystem) |
| CSS linting | Yes (built-in) | Needs separate stylelint |
| LSP/IDE support | Built-in LSP server | Separate extensions per tool |
| Lint rules count | 491+ | ~300 core + plugins |
3. Installing and Configuring Biome
3.1. Installation
# Install in your project
npm install --save-dev --save-exact @biomejs/biome
# Or use pnpm/bun
pnpm add -D @biomejs/biome
bun add -D @biomejs/biome
# Create default configuration
npx @biomejs/biome init
3.2. Basic biome.json Configuration
{
"$schema": "https://biomejs.dev/schemas/2.4.0/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noExcessiveCognitiveComplexity": {
"level": "warn",
"options": { "maxAllowedComplexity": 15 }
}
},
"suspicious": {
"noExplicitAny": "error"
},
"style": {
"useConst": "error",
"noNonNullAssertion": "warn"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "all",
"semicolons": "always"
}
},
"css": {
"linter": { "enabled": true },
"formatter": { "enabled": true }
}
}
3.3. Running Biome
# Format all files
npx biome format --write .
# Lint with auto-fix
npx biome lint --write .
# Run both (check = lint + format)
npx biome check --write .
# CI mode — check only, no modifications
npx biome ci .
4. Biome's Internal Architecture
graph TD
A["Source Files
JS/TS/JSX/CSS/JSON"] --> B["Biome Core
Rust Engine"]
B --> C["Parser
Concrete Syntax Tree"]
C --> D{"Parallel Processing"}
D --> E["Formatter
Pretty-print CST"]
D --> F["Linter
491+ Rules Analysis"]
D --> G["Type Resolver
Type-aware rules"]
E --> H["Formatted Output"]
F --> I["Diagnostics
+ Auto-fix suggestions"]
G --> F
style B fill:#e94560,stroke:#fff,color:#fff
style C fill:#2c3e50,stroke:#fff,color:#fff
style D fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style E fill:#4CAF50,stroke:#fff,color:#fff
style F fill:#16213e,stroke:#fff,color:#fff
style G fill:#2c3e50,stroke:#fff,color:#fff
Biome's processing pipeline — parse once, lint + format in parallel
The key insight: Biome parses source code only once into a Concrete Syntax Tree (CST), then both the formatter and linter share this tree. ESLint + Prettier must parse separately — double parsing wastes significant time on large codebases.
5. New Features in Biome v2.x (2026)
5.1. Type-Aware Linting
Starting from v2.0, Biome supports lint rules based on type information. The first and most requested rule: noFloatingPromises.
// ❌ Biome will flag this — Promise not awaited
async function fetchData() {
fetch('/api/users'); // noFloatingPromises: Promise returned but not awaited
}
// ✅ Correct
async function fetchData() {
await fetch('/api/users');
}
5.2. Plugin System with GritQL
Biome v2.0 introduces a plugin system using GritQL — a query language for code patterns. You can write custom lint rules without writing Rust:
{
"plugins": ["./biome-plugins/no-console-in-prod.grit"]
}
// no-console-in-prod.grit
`console.$method($args)` where {
$method <: or { "log", "debug", "info" },
// Allow console.error and console.warn
}
5.3. Linter Domains — Auto-Enable Rules by Dependencies
{
"linter": {
"domains": {
"react": "error",
"next": "warn",
"solid": "off"
}
}
}
Biome automatically detects package.json dependencies and suggests enabling the corresponding domain. If your project uses React, all rules in the react domain (JSX accessibility, hooks rules, etc.) are automatically activated.
5.4. Embedded CSS + GraphQL in JavaScript
// Biome v2.4 automatically formats and lints CSS-in-JS
const Button = styled.button`
background: #e94560;
padding: 12px 24px;
border: none;
border-radius: 8px;
color: #fff;
cursor: pointer;
&:hover {
background: #c73854;
}
`;
// GraphQL queries are also linted + formatted
const GET_USERS = gql`
query GetUsers($limit: Int!) {
users(limit: $limit) {
id
name
email
}
}
`;
6. Migrating from ESLint + Prettier to Biome
6.1. Automatic Migration
# Biome reads your ESLint/Prettier config and converts it
npx @biomejs/biome migrate eslint --write
npx @biomejs/biome migrate prettier --write
The migrate eslint command reads your .eslintrc.* and maps corresponding rules to biome.json. Rules without equivalents are listed for your review.
6.2. Migration Strategy for Large Projects
graph LR
A["Phase 1
Formatter only"] --> B["Phase 2
Lint recommended"]
B --> C["Phase 3
Strict rules"]
C --> D["Phase 4
Remove ESLint"]
style A fill:#4CAF50,stroke:#fff,color:#fff
style B fill:#2c3e50,stroke:#fff,color:#fff
style C fill:#e94560,stroke:#fff,color:#fff
style D fill:#16213e,stroke:#fff,color:#fff
4-phase migration roadmap for large projects
Phase 1 — Formatter only: Enable Biome formatter, disable Prettier. This is the safest step as it only changes formatting.
{
"formatter": { "enabled": true },
"linter": { "enabled": false }
}
Phase 2 — Lint recommended: Enable linter with recommended rules. Optionally keep ESLint for Vue SFC files (Biome doesn't fully support Vue SFC yet).
Phase 3 — Strict rules: Enable additional strict rules, address remaining violations.
Phase 4 — Remove ESLint: Completely remove ESLint + Prettier + config packages.
# Cleanup after migration
npm uninstall eslint prettier eslint-config-prettier \
eslint-plugin-vue @typescript-eslint/eslint-plugin \
@typescript-eslint/parser
# Remove old config files
rm .eslintrc.js .prettierrc .eslintignore .prettierignore
7. CI/CD and IDE Integration
7.1. 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: 22
- run: npm ci
- name: Biome CI Check
run: npx biome ci .
7.2. VS Code Extension
Biome provides an official VS Code extension with a built-in LSP server:
// .vscode/settings.json
{
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
}
}
How Fast Is Format on Save?
Biome formats a file in ~1-2ms (Prettier takes ~50-100ms). With format-on-save, you'll never notice any delay — files are formatted instantly when you press Ctrl+S.
8. Biome with Vue.js Projects
Vue SFC Limitation
As of v2.4, Biome does not yet support parsing/linting/formatting the <template> and <style> sections in Vue Single File Components (.vue). Biome only processes the <script> and <script setup> sections. Full Vue SFC support is on the 2026 roadmap.
Practical strategy for Vue projects:
- Use Biome for all
.ts,.tsx,.json,.cssfiles - Keep
eslint-plugin-vueonly for.vuefiles (template rules) - Disable Prettier entirely — Biome handles formatting for non-Vue files
{
"files": {
"ignore": ["**/*.vue"]
},
"formatter": { "enabled": true },
"linter": { "enabled": true }
}
9. Real-World Monorepo Benchmarks
| Task | ESLint + Prettier | Biome | Speedup |
|---|---|---|---|
| Lint 5,000 TS files | 22.4s | 0.5s | 45x |
| Format 5,000 files | 6.8s | 0.2s | 34x |
| CI check (lint + format) | 31.2s | 0.6s | 52x |
| IDE feedback (single file) | 50-100ms | 1-2ms | 50x |
| npm install (deps) | ~45MB (8 packages) | ~12MB (1 package) | 73% smaller |
10. Conclusion
Biome isn't just "faster ESLint + Prettier" — it represents a new generation of JavaScript tooling written in system-level languages. With 25-50x faster speed, a single configuration file, type-aware linting, GritQL plugin system, and built-in CSS/GraphQL support, Biome is gradually becoming the new standard for code quality in the JavaScript/TypeScript ecosystem.
If you're starting a new project — there's no reason not to use Biome. If you're maintaining a legacy project with ESLint + Prettier — the migration path is clear with biome migrate. Your CI pipeline will be faster, your DX will be smoother, and you'll have fewer config files scattered across your project root.
References
Apache Kafka 4.x: The Event Streaming Era Without ZooKeeper
gRPC in .NET 10 — High-Performance Microservices Communication with Protobuf
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.