Bun 1.4.4 ships a formatter: 59 milliseconds on Prettier's own repo, 286x faster

bun fmt reads your existing Prettier config and plugins, running 59.7 ms against 17.1 s on Prettier's own repository, 48 MB against 459 MB. What matters is how it proves identical output: byte comparison plus a semantic re-parse check.

Bun 1.4.4 landed on October 22 and the headline is a built-in formatter: bun fmt. It reads your existing Prettier or oxfmt config, accepts Prettier plugins, and finishes 59.7 milliseconds on Prettier’s own repository — where Prettier 3.9.10 takes 17.1 seconds. 286x, at 48 MB versus 459 MB of peak memory.

The number is catchy, but what interests me more is how it proves it did not break your code.

What it covers

One bun fmt src/index.ts src/styles.css handles JavaScript, TypeScript, JSX, Flow, CSS, SCSS, Less, HTML, Vue, Svelte, Angular, Lightning Web Components, MJML, JSON, JSONC, JSON5, YAML, TOML, Markdown, MDX, GraphQL and Handlebars. Embedded code too: <style> inside HTML, code fences in Markdown, css template literals in JS.

Better still, three common plugins are built in:

You used to install Now
prettier-plugin-tailwindcss built in; sorts classes with the project’s tailwindcss v3/v4
prettier-plugin-packagejson built in; same key order, values untouched
prettier-plugin-svelte built in; formats .svelte by default, matching 4.1.1

The Bun 1.4.4 release notes — bun fmt is the first section

Where the speed comes from

Same repository, same files, same config:

Project Files bun fmt Baseline Ratio
Prettier repo 2,616 59.7 ms 17.1 s (Prettier 3.9.10) 286x
RSSHub 7,121 97.3 ms 298.5 ms (oxfmt 0.74.0) 3.0x
redocly-cli 3,397 62.4 ms 217.5 ms (oxfmt) 3.4x
vite 2,537 65.2 ms 406.7 ms (oxfmt) 6.2x
fumadocs 2,452 44.6 ms 1,395 ms (oxfmt) 31x

Against Prettier it is an order of magnitude; against oxfmt — already a Rust implementation — it is 3x to 31x. Which says the bottleneck is not “JS versus Rust” but how the parser and printer are built: Bun’s formatter uses its own parser and reuses the runtime’s existing string and allocation machinery.

For a site build like mine the formatter time is not the pain point: a few hundred files take Prettier a second or two. But it runs on every PR, often serially after lint and typecheck. A 300 ms tool and a 20 s tool have completely different psychological cost in a dev loop: the first can hang off pre-commit, the second can only live in CI.

The comparison table with file counts and peak memory

How “identical output” is proven

A formatter is a zero-decision tool: it should have no taste. So the only bar for swapping implementations is output equality. Bun offers three kinds of evidence:

  1. Byte comparison against the Prettier plugins: 13,654 of 13,952 JS/TS files (97.9%) identical; 2,148 of 2,176 HTML/Vue/Angular/CSS/Markdown files (98.7%) identical; 15 of 15 Tailwind projects identical; 13,644 of 13,670 real-world package.json files (99.8%) byte-identical.
  2. Running Prettier’s own test suite: Bun’s CI runs Prettier 3.9.9’s formatting tests on every commit, and a test passes only if output is byte-for-byte identical. JS 1,356/1,357, JSX 186/186, TS 756/756, JSON 785/785, Markdown 1,569/1,572, YAML 1,554/1,621 (95.9%, the weakest).
  3. --debug-check: re-parse after formatting and fail if the meaning changed — the same switch Prettier has.

The second is the one I trust most. Running your competitor’s test suite is the strongest compatibility evidence available; self-written cases always lean toward your own implementation.

The intentional differences

One class of difference is worth reading closely: inputs where Prettier changes the meaning of the code.

Input Prettier 3.9.9 bun fmt
font-family: Font\ Awesome in CSS becomes Font\Awesome, \A reads as a hex escape preserved
CSS selector x |b becomes x|b, a namespace selector instead of a descendant preserved
<!DOCTYPE html> in Handlebars dropped preserved
A Handlebars <script> with a // comment lines joined, comment swallows the next line preserved

The first two are escapes being eaten, which is the most dangerous form of drift in a formatter: the diff looks like a removed space.

Install or not

My call: turn it on for new projects; for mature repos run a full-tree diff on a branch first. Not because of speed, but because of that 2.1%: in a mature repository, 2% of files being re-indented produces one enormous diff, and mixing that into a feature PR destroys review.

Two details worth noting:

  • If your config uses a plugin bun fmt does not support (say prettier-plugin-jsdoc), it prints the plugin name, skips the affected files, and exits with code 2. That is the right behavior: fail loudly rather than skip silently.
  • .svelte is formatted by default; disable it with svelte = false under [fmt] or --no-svelte.

The bun fmt docs page — configuration mirrors Prettier

One line

Bun has spent two years pulling the toolchain into the runtime: bundler, test runner, package manager, and now a formatter. The point of 1.4.4 is not the 17 seconds saved — it is that byte comparison plus the competitor’s test suite turns “a drop-in replacement” into a verifiable claim.

The GitHub release page, 38 build artifacts

← Back to all posts

Comments

…