blog.dopana

Back

In the modern JavaScript/TypeScript world, we’re witnessing the rise of high-performance Rust tools. While Biome has established itself as an all-in-one toolchain, Oxc takes a different approach with specialized tools: Oxfmt (formatter) and Oxlint (linter). This article introduces these two tools and compares their architecture with Biome.

What is Oxfmt?#

Oxfmt (/oʊ-ɛks-fɔːr-mæt/) is a high-performance formatter for the JavaScript ecosystem, built on the Oxc compiler stack. It’s designed to deliver full compatibility with Prettier while dramatically improving performance.

Key Features of Oxfmt#

Multi-language Support#

Oxfmt supports many file formats, with some handled by the native Rust engine and others delegated to the bundled Prettier:

Native formats (run entirely in Rust):

  • JavaScript/JSX: .js, .jsx, .mjs, .cjs
  • TypeScript/TSX: .ts, .tsx, .mts, .cts, .d.ts
  • JSON/JSONC/JSON5: .json, .jsonc, .json5
  • CSS/SCSS/Less: .css, .scss, .less
  • GraphQL: .graphql, .gql
  • TOML: .toml
  • YAML: .yml, .yaml

Delegated formats (use bundled Prettier):

  • HTML, Angular, Vue, Svelte
  • Markdown, MDX
  • Handlebars, MJML

Built-in Features#

Oxfmt includes features that typically require external Prettier plugins:

  • Import sorting: Sort imports with configurable options
  • Tailwind CSS class sorting: Automatic Tailwind class sorting (compatible with prettier-plugin-tailwindcss)
  • package.json field sorting: Automatic package.json field organization
  • Embedded formatting: Format code embedded in template literals (CSS-in-JS, GraphQL, etc.)

Performance#

According to benchmarks, Oxfmt is:

  • ~30x faster than Prettier
  • 2x faster than Biome

Prettier Compatibility#

Oxfmt currently passes 100% of Prettier’s JavaScript and TypeScript conformance tests. When migrating from recent Prettier versions, formatting differences should not occur.

Oxfmt Architecture#

Oxfmt 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 --> tailwind_sort[Tailwind Sort]
    tailwind_sort --> Printer[Printing]
    Printer --> Output[Formatted Text]
  1. IR Generation: AST traversal using Format trait
  2. IR Transformation: Apply transformations like sort_imports and Tailwind sorting
  3. Printing: Printer consumes IR and renders final output

[!NOTE] Oxfmt formatter core is ported from Biome’s biome_formatter crate, but with completely language-agnostic design.

What is Oxlint?#

Oxlint (/oʊ-ɛks-lɪnt/) is a high-performance linter for JavaScript and TypeScript built on the Oxc compiler stack. It’s designed as a drop-in ESLint replacement with superior performance.

Key Features of Oxlint#

Broad Rule Coverage#

Oxlint includes 870+ built-in rules covering the most popular linter plugins:

  • ESLint core rules: Basic JavaScript rules
  • TypeScript rules: Including type-aware rules
  • Popular plugins: React, Jest, Vitest, Import, Unicorn, jsx-a11y
  • Custom JS plugins: Compatible with ESLint plugin ecosystem

Type-aware Linting#

Oxlint uses the native Go port of the TypeScript compiler (tsgo aka TypeScript 7), providing:

  • Full TypeScript compatibility
  • Same type system behavior as TypeScript
  • Type-aware linting aligned with TypeScript semantics

Multi-file Analysis#

Oxlint supports multi-file analysis as a first-class capability:

  • Builds project-wide module graph
  • Shares parsing and resolution across rules
  • Improves checks that depend on cross-file imports
  • Avoids the performance cliff often seen with rules like import/no-cycle in ESLint

Performance#

Oxlint is built for large repositories and CI environments:

  • 50-100x faster than ESLint
  • Architecture removes structural bottlenecks limiting ESLint performance
  • Multi-threaded file processing

Oxlint Architecture#

Oxlint uses parallel execution architecture with dual branch strategy:

graph TB
    CLI[CLI Interface] --> LintRunner[LintRunner]
    LintRunner --> LintService[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
    
    LintService --> DiagnosticService[DiagnosticService]
    DiagnosticService --> Output[Output]

Key Components#

  1. LintService: Orchestrates linting with parallel execution
  2. Runtime: Manages paths and file discovery
  3. LintContext: Contains Semantic analysis context
  4. Linter: Core engine executing rules on AST
  5. Rule Trait: Defines hooks for rule implementation

Dual Branch Strategy#

  • Small files (<200k nodes): Iterate (nodes → rules)
  • Large files (≥200k nodes): Iterate (rules → nodes) with RULE_BUCKETS
  • This avoids CPU cache thrashing on large files

Architecture Comparison with Biome#

1. Design Philosophy#

FeatureOxfmt/OxlintBiome
ApproachSpecialized toolsAll-in-one toolchain
IntegrationSeparate, can be used independentlyIntegrated formatter + linter
DeploymentTraditional CLIDaemon process for IDE
ConfigurationSeparate config filesUnified biome.json

2. Formatter Architecture#

FeatureOxfmtBiome
Stages3 stages (IR Gen + Transform + Printing)2 stages (Lowering + Printing)
IR DesignFormatElement in oxc_formatter_coreFormatElement in biome_formatter
Transformationssort_imports, Tailwind sorting, package.json sortMinimal built-in transforms
Prettier Compatibility100% test pass, built-in compatibilityPrettier-inspired but different output
Language SupportNative Rust + delegated PrettierNative Rust implementation

3. Linter Architecture#

FeatureOxlintBiome
Rule Count870+ built-in rulesFewer rules, focus on core
Type-aware LintingTsgo (TypeScript 7 Go port)Built-in TypeScript support
Multi-file AnalysisFirst-class feature, module graphLimited support
Parallel ExecutionDual branch strategyVia WorkspaceServer
Plugin SystemJS plugins (alpha) for ESLint compatibilityNative plugin architecture

4. Performance#

FeatureOxfmt/OxlintBiome
Formatter Speed30x faster than Prettier, 2x faster than Biome10-20x faster than Prettier
Linter Speed50-100x faster than ESLintSimilar to Oxlint
MemoryArena allocator, zero-copyRowan-based infrastructure
StartupTraditional CLI, fast startupDaemon process, slower initial start

5. Migration Path#

FeatureOxfmt/OxlintBiome
From PrettierDirect migration, 100% compatibilityRequires adjustment to different output
From ESLintDrop-in replacement, 870+ rulesRequires rule configuration changes
Config Migration--migrate=prettier, --migrate=biomeManual config conversion
Tooling IntegrationPrettier-compatible CLICustom Biome CLI

When to Use Which?#

Choose Oxfmt + Oxlint when#

  • You want maximum performance for CI/CD
  • Need Prettier compatibility without changing output
  • Want separate tools for formatter and linter
  • Migrating from ESLint + Prettier with minimum disruption
  • Need Tailwind CSS integration built-in
  • Want type-aware linting with accurate TypeScript semantics

Choose Biome when#

  • You want a unified toolchain in one package
  • Need multi-language support (CSS, HTML, GraphQL) native
  • Want daemon process for better IDE integration
  • Team wants single configuration file
  • Don’t need absolute Prettier compatibility

Usage Examples#

Oxfmt#

Oxlint#

# Install
npm install -D oxlint

# Lint files
oxlint src/

# Type-aware linting
oxlint --tsconfig tsconfig.json src/

# Multi-file analysis
oxlint --enable-import-plugin src/
bash

Biome#

# Install
npm install -D @biomejs/biome

# Format and lint
biome check src/

# Format only
biome format src/

# Lint only
biome lint src/

# Watch mode
biome check --watch .
bash

Conclusion#

Oxfmt and Oxlint represent the specialized tools approach with maximum performance and Prettier/ESLint compatibility, while Biome provides a unified toolchain with integrated experience.

The choice between the two ecosystems depends on project priorities: performance & compatibility vs integration & simplicity, separate tools vs unified toolchain, existing ecosystem compatibility vs new toolchain adoption.

Both represent the future of JavaScript/TypeScript tooling with high Rust performance, but serve different use cases in the development workflow.

References#