Oxfmt Overview

What the Oxc formatter (oxfmt) does, how it works, and where it stands. Verified against the source code in _repos/oxc-project-oxc/ at v0.40.0.

What It Does

Oxfmt is a Prettier-compatible code formatter built in Rust. It reads JavaScript/TypeScript source code, parses it with the Oxc parser, converts the AST into Prettier’s intermediate representation (IR), and prints formatted output. The goal: produce the same output as Prettier, but much faster.

Current Status

Actively developed, approaching Prettier parity. The npm package is oxfmt (v0.40.0). Prettier conformance is tracked via the full Prettier test suite, run with cargo run -p oxc_prettier_conformance.

Architecture

The formatter spans three locations in the Oxc monorepo:

LocationRole
crates/oxc_formatter/Core formatting engine (Rust)
apps/oxfmt/CLI binary + Node.js bindings via NAPI
npm/oxfmt/npm distribution package

Data Flow

Source Text
    |
    v
oxc_parser  ->  AST (arena-allocated)
    |
    v
oxc_formatter  ->  Prettier IR (Format trait)
    |
    v
Printer  ->  Formatted output string

The Format trait walks AST nodes and emits Prettier IR elements (tokens, groups, indents, line breaks). The printer then takes this IR and makes line-breaking decisions based on the configured line width.

Two CLI Modes

  1. Pure Rust CLI - cargo build --no-default-features. Supports JS/TS and TOML formatting only. No embedded language support. Entry point: main.rs.

  2. Hybrid JS/Rust CLI - Built with pnpm build. Full feature set including stdin, LSP integration, and embedded language formatting (CSS-in-JS, GraphQL-in-JS). Entry point: src-js/cli.ts calling run_cli() from main_napi.rs.

The hybrid mode uses tinypool (a worker pool) for the Node.js side and NAPI-RS for the Rust bindings.

Format Options

All options from crates/oxc_formatter/src/options.rs, with their defaults:

OptionDefaultValues
indentStyle"space""space", "tab"
indentWidth20-24
lineWidth1001-320
quoteStyle"double""double", "single"
jsxQuoteStyle"double""double", "single"
quoteProperties"as-needed""as-needed", "preserve", "consistent"
trailingCommas"all""all", "es5", "none"
semicolons"always""always", "as-needed"
arrowParentheses"always""always", "as-needed"
bracketSpacingtruetrue, false
bracketSameLinefalsetrue, false
expand"auto""auto", "never"
sortImportsdisabledObject with groups, custom groups, newlines config
sortTailwindcssdisabledObject with config path, stylesheet, functions, attributes

Not Yet Implemented

These Prettier options are defined in the code but marked as not supported yet:

  • experimentalOperatorPosition - controls operator placement in wrapped binary expressions
  • experimentalTernaries - curious ternary formatting

Embedded Language Support

The hybrid CLI (NAPI mode) supports formatting embedded languages:

  • CSS-in-JS - CSS within template literals (styled-components, etc.)
  • GraphQL-in-JS - GraphQL queries in tagged templates
  • Vue - partial support for .vue single-file components
  • TOML - supported in the pure Rust CLI too

Controlled via the embeddedLanguageFormatting option ("auto" or "off").

Config File

Oxfmt looks for .oxfmtrc.json (or oxfmtrc.jsonc). The config supports a $schema for IDE autocomplete:

{
  "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxfmt/configuration_schema.json",
  "indentStyle": "space",
  "indentWidth": 2,
  "lineWidth": 80,
  "semicolons": "as-needed",
  "quoteStyle": "single",
  "ignorePatterns": ["dist/", "generated/"]
}

File-specific overrides are supported via the overrides key, matching Prettier’s pattern.

Why Use Oxfmt Over Prettier

Speed. Same reason as oxlint vs ESLint. Oxfmt uses the same Oxc parser, arena allocator, and rayon-based parallelism that makes the rest of the Oxc toolchain fast. For large codebases, formatting time drops from seconds to milliseconds.

The trade-off: oxfmt is newer and still reaching full Prettier parity. For projects that need 100% Prettier compatibility today, run both and compare output. For projects that can tolerate minor differences, oxfmt is a drop-in replacement.

Next Steps