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 |

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.

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:
- 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.jsonfiles (99.8%) byte-identical. - 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).
--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. .svelteis formatted by default; disable it withsvelte = falseunder[fmt]or--no-svelte.

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.


Comments
…