Biome vs Oxc Architecture Comparison
Architecture analysis and comparison between Biome and Oxc - two Rust tools for JavaScript/TypeScript
In the modern JavaScript/TypeScript development world, Biome ↗ and Oxc ↗ are two prominent Rust tools that deliver high performance for linting and formatting. Both are written in Rust but have different design philosophies and architectures. This article will dive deep into each tool’s architecture and compare them.
What is Biome?#
Biome is a comprehensive toolchain for web projects, providing formatter and linter usable via CLI and LSP. It’s designed to replace Prettier and ESLint with higher performance in a single integrated package.
Biome Architecture#
Biome uses a server-client architecture with a daemon running in the background:
graph TB
subgraph "Biome Architecture"
CLI[CLI Interface]
LSP[LSP Server]
Daemon[Daemon Process]
Workspace[WorkspaceServer]
Handlers[Language Handlers]
Foundation[Foundation Layer]
end
CLI --> Daemon
LSP --> Daemon
Daemon --> Workspace
Workspace --> Handlers
Handlers --> Foundation
Architecture Layers#
-
Foundation Layer (
biome_rowan,biome_parser,biome_formatter,biome_analyze)- Provides reusable primitives
- Rowan-based parsing infrastructure
- Common formatting IR
-
Language Layer (per-language crates)
biome_js_parser,biome_js_formatter,biome_js_analyzebiome_json_parser,biome_json_formatter,biome_json_analyze- Similar for CSS, HTML, GraphQL
-
Service Layer (
biome_service)- Orchestrates operations via
WorkspaceServer - Manages state and caching
- Orchestrates operations via
-
Interface Layer (
biome_cli,biome_lsp,biome_wasm)- Provides multiple consumption methods
Biome’s Formatter#
Biome uses a two-stage formatting system:
graph LR
CST[CST from Parser] --> Lowering[Lowering Stage]
Lowering --> IR[FormatElement IR]
IR --> Printer[Printing Stage]
Printer --> Output[Formatted Text]
- Lowering Stage: Converts CST to language-agnostic IR (
FormatElement) - Printing Stage: Printer consumes IR and decides layout, line breaks based on options
What is Oxc?#
Oxc (The Oxidation Compiler) is a collection of high-performance JavaScript/TypeScript tools written in Rust. It’s designed as a modular, composable set of compiler components that can be used independently or together to build complete toolchains.
Oxc Architecture#
Oxc uses a layered design with modular components:
graph TB
subgraph "Oxc Architecture"
Apps[Applications]
Core[Core Libraries]
Foundation[Foundation Libraries]
end
Apps --> Core
Core --> Foundation
Apps --> oxlint[oxlint]
Apps --> LSP[Language Server]
Apps --> NAPI[NAPI Bindings]
Core --> Parser[Parser]
Core --> Semantic[Semantic]
Core --> Linter[Linter]
Core --> Transformer[Transformer]
Core --> Minifier[Minifier]
Core --> Codegen[Codegen]
Foundation --> AST[AST]
Foundation --> Allocator[Allocator]
Foundation --> Diagnostics[Diagnostics]
Foundation --> Span[Span]
Foundation --> Syntax[Syntax]
Architecture Principles#
- Zero-Copy: Uses arena allocator (
oxc_allocator) for zero-copy operations - Visitor Pattern: AST traversal with automatic visitor generation
- Shared Foundation: Common error reporting, source positions, syntax definitions
Oxc’s Linter#
Oxlint uses parallel execution architecture with dual branch strategy:
graph TB
LintService[LintService] --> Runtime[Runtime]
Runtime --> process_source[process_source]
process_source --> Parser[Parser]
Parser --> AST[AST]
AST --> LintContext[LintContext]
LintContext --> Linter[Linter]
Linter --> execute_rules[execute_rules]
execute_rules --> strategy1[Strategy 1: nodes → rules]
execute_rules --> strategy2[Strategy 2: rules → nodes]
strategy1 --> RULE_BUCKETS[RULE_BUCKETS]
strategy2 --> RULE_BUCKETS
- Dual Branch Strategy: Switches between (nodes → rules) or (rules → nodes) based on file size
- Parallel Execution: Uses rayon for parallel file processing
- Type-Aware Linting: Supports type-aware linting
Oxc’s Formatter (oxfmt)#
Oxc formatter uses a three-stage formatting system:
graph LR
AST[AST from Parser] --> IRGen[IR Generation]
IRGen --> IR[FormatElement IR]
IR --> Transform[IR Transformation]
Transform --> sort_imports[sort_imports]
sort_imports --> Printer[Printing]
Printer --> Output[Formatted Text]
- IR Generation: AST traversal using
Formattrait - IR Transformation: Applies transformations like
sort_imports - Printing: Printer consumes IR and renders final output
[!NOTE] Oxc formatter core is ported from Biome’s
biome_formattercrate, but with completely language-agnostic design.
Detailed Comparison#
1. Design Philosophy#
| Feature | Biome | Oxc |
|---|---|---|
| Goal | All-in-one toolchain replacing Prettier + ESLint | Modular components usable independently |
| Multi-language | Supports JS/TS, JSON, CSS, HTML, GraphQL | Focused on JS/TS with expansion plans |
| Deployment | Daemon process for IDE integration | Traditional CLI with NAPI bindings |
2. Memory Management#
| Feature | Biome | Oxc |
|---|---|---|
| Allocator | Rowan-based infrastructure | Arena allocator (oxc_allocator) |
| Zero-Copy | Yes, but less explicit | Yes, as core design principle |
| AST Storage | Rowan syntax tree | Arena-based AST nodes |
3. Performance Optimization#
| Feature | Biome | Oxc |
|---|---|---|
| Parallel Execution | Yes, via WorkspaceServer | Yes, using rayon |
| Caching | Daemon process cache | Runtime cache in LintService |
| Rule Execution | Sequential execution | Dual branch strategy based on file size |
4. Extensibility#
| Feature | Biome | Oxc |
|---|---|---|
| Plugin System | Supports plugins | JS plugins (alpha) for ESLint compatibility |
| Language Support | ExtensionHandler pattern | Module crates per language |
| Custom Rules | Via biome configuration | Via rule configuration |
5. Formatting Architecture#
| Feature | Biome | Oxc |
|---|---|---|
| Stages | 2 stages (Lowering + Printing) | 3 stages (IR Gen + Transform + Printing) |
| IR Design | FormatElement in biome_formatter | FormatElement in oxc_formatter_core |
| Comment Handling | Integrated in formatter | Cursor-based comment system |
| Prettier Compatibility | Yes, with testing | Yes, as design goal |
When to Use Which?#
Choose Biome when#
- You want an all-in-one solution replacing both Prettier and ESLint
- Need multi-language support (CSS, HTML, GraphQL)
- Want daemon process for better IDE integration
- Team wants unified toolchain with simple configuration
Choose Oxc when#
- You want modular components that can be used independently
- Need maximum performance for CI/CD environments
- Want type-aware linting with TypeScript semantics
- Building custom toolchain from components
Usage Examples#
Biome#
# Install
npm install -D @biomejs/biome
# Format and lint a file
biome check src/file.ts
# Format and lint entire project
biome check .
# Watch mode for development
biome check --watch .bashOxc#
# Install oxlint
npm install -D oxlint
# Lint a file
oxlint src/file.ts
# Lint entire project with parallel execution
oxlint src/
# Type-aware linting
oxlint --tsconfig tsconfig.json src/bashConclusion#
Both Biome and Oxc represent the future of JavaScript/TypeScript tooling with high Rust performance. Biome excels at all-in-one experience with multi-language support, while Oxc shines at modular design and maximum performance.
The choice between the two tools depends on your project’s specific needs: unified toolchain vs flexible components, multi-language support vs JS/TS focus, IDE integration vs CI performance.