Bun v1.4.4
To install Bun
curl
curl -fsSL https://bun.sh/install | bashnpm
npm install -g bunpowershell
powershell -c "irm bun.sh/install.ps1|iex"scoop
scoop install bunbrew
brew tap oven-sh/bunbrew install bundocker
docker pull oven/bundocker run --rm --init --ulimit memlock=-1:-1 oven/bunTo upgrade Bun
bun upgradebun fmt: a formatter built into Bun#
bun fmt is an incredibly fast, Prettier-compatible code formatter that works with your existing Prettier or oxfmt config.
bun fmtsrc/index.ts
src/styles.css
Formatted 2 files, 2 unchanged [5.59ms]It formats 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 is formatted too, like <style> in HTML, code blocks in Markdown and css`...` templates in JavaScript.
In Prettier's own repository (2,616 files, with their config), bun fmt --check takes 60 ms and Prettier takes 17 seconds:
Tool | Time | Peak memory |
|---|---|---|
| 59.7 ms | 48 MB |
Prettier 3.9.10 | 17.1 s | 459 MB |
That's 286x faster. On vitest, date-fns, monkeytype and h3, it's 234x to 425x faster than Prettier 3.9.9.
On projects that already use oxfmt, with their own config, it's 3x to 6x faster than oxfmt 0.74.0:
Project | Files |
| oxfmt 0.74.0 | Faster | Memory |
|---|---|---|---|---|---|
RSSHub | 7,121 | 97.3 ms | 298.5 ms | 3.0x | 42 vs 95 MB |
redocly-cli | 3,397 | 62.4 ms | 217.5 ms | 3.4x | 61 vs 107 MB |
vite | 2,537 | 65.2 ms | 406.7 ms | 6.2x | 64 vs 137 MB |
fumadocs | 2,452 | 44.6 ms | 1,395 ms | 31x | 48 vs 179 MB |
Both tools see the same files, exit 0 and leave the tree unchanged.
Reproduce these numbers
Each project is a fresh clone at a pinned commit. The oxfmt projects have no node_modules.
vite
bun install -g oxfmt@0.74.0git clone https://github.com/vitejs/vite && cd vitegit checkout 4ca25e1d3a24hyperfine --warmup 2 "oxfmt ." "bun fmt ."redocly-cli
git clone https://github.com/Redocly/redocly-cli && cd redocly-cligit checkout 82da67d6ea5bhyperfine --warmup 3 --runs 20 "oxfmt --check ." "bun fmt --check ."RSSHub
git clone https://github.com/DIYgod/RSSHub && cd RSSHubgit checkout 8776927c78dehyperfine --warmup 3 --runs 20 "oxfmt --check ." "bun fmt --check ."fumadocs
git clone https://github.com/fuma-nama/fumadocs && cd fumadocsgit checkout bc86bbb0d406hyperfine --warmup 3 --runs 20 "oxfmt --check ." "bun fmt --check ."prettier
git clone https://github.com/prettier/prettier && cd prettiergit checkout df39b5b60a28bun install --ignore-scriptshyperfine --warmup 3 "bun fmt --no-script . --check" "node node_modules/prettier/bin/prettier.cjs . --check"The same runs on one core, and on only vite's JavaScript and TypeScript files ('**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'):
Run |
| oxfmt 0.74.0 | Faster |
|---|---|---|---|
vite, 1,608 JS and TS files | 52.2 ms | 188.3 ms | 3.6x |
RSSHub, one core | 621.6 ms | 1,212 ms | 1.9x |
redocly-cli, one core | 375.1 ms | 645.5 ms | 1.7x |
fumadocs, one core | 255.2 ms | 5,608 ms | 21x |
vite: 16-core M4 Max MacBook Pro, macOS 26.7. Mean.
Everything else: Intel Xeon Platinum 8488C, 8 physical cores pinned with
taskset, Amazon Linux 2023, xfs on NVMe, warm file cache. Median.
bun fmt wouldn't exist without Prettier, Biome and Oxc. It's a port of Prettier, and the JavaScript and TypeScript printer is a port of oxc_formatter, which is a port of Biome's formatter.
Thank you to the Prettier, Biome and Oxc teams for years of great work.
Read more in the docs.
bun fmt --check#
--check lists the files that need formatting without writing anything. It exits with code 1 if there are any.
bun fmt --checksrc/index.ts
src/styles.css
2 files need formatting. Run bun fmt to fix them.bun fmt --staged and --changed#
--staged only formats the files you're about to commit and re-stages them, so you don't need lint-staged.
.git/hooks/pre-commit
#!/bin/sh
bun fmt --staged--changed formats the files that differ from your default branch. Pass a ref to compare against something else.
bun fmt --changedbun fmt --changed=origin/devUse your Prettier or oxfmt config#
bun fmt reads .prettierrc*, prettier.config.*, "prettier" in package.json, overrides, .editorconfig and .prettierignore. It also reads .oxfmtrc.json, .oxfmtrc.jsonc and oxfmt.config.ts (or .mts). It accepts the same CLI flags as Prettier or oxfmt, and // prettier-ignore comments work.
"scripts": {
"format": "prettier --write ."
"format": "bun fmt"
}Import sorting is built in, so you can leave @trivago/prettier-plugin-sort-imports, @ianvs/prettier-plugin-sort-imports and prettier-plugin-organize-imports in plugins. Languages that need a Prettier plugin, like Astro, fall back to the Prettier installed in your project.
The command is bun fmt, like cargo fmt, go fmt, deno fmt and zig fmt. bun format still runs your format script.
bun fmt --doctor shows how Bun interprets your config and which packages you can uninstall.
Options in bunfig.toml#
All of Prettier's options are supported under the same names. Each one is also available as a flag, like --print-width 100 or --no-semi. bun fmt --init creates the [fmt] section.
bunfig.toml
[fmt]
printWidth = 100
semi = false
sortImports = true
sortTailwindcss = true
sortPackageJson = true
jsdoc = true
[[fmt.overrides]]
files = ["*.test.ts"]
options = { printWidth = 120 }sortImports, sortTailwindcss, sortPackageJson and jsdoc are off by default, and don't need a Prettier or oxfmt config. sortImports groups imports, sorts the names in { } and merges duplicate imports from the same module.
In a monorepo, bun fmt walks up from the working directory to the nearest bunfig.toml with a [fmt] section. Without a Prettier config, bun fmt also formats TOML. It skips *.min.js, *.min.css and lockfiles unless you pass them explicitly.
Prettier's Tailwind, package.json and Svelte plugins are built in#
bun fmt does the work of prettier-plugin-tailwindcss, prettier-plugin-packagejson and prettier-plugin-svelte, so you don't need them installed. You can leave them in plugins, and their options are supported.
// Before
<button className="text-white px-4 sm:px-8 py-2 bg-sky-700 hover:bg-sky-800" />
// After
<button className="bg-sky-700 px-4 py-2 text-white hover:bg-sky-800 sm:px-8" />Tailwind classes are sorted with your project's tailwindcss, version 3 or 4. If it isn't installed, they're left as they are.
We compared the output against Prettier 3.9.9 with version 0.8.1 of the plugin, on Tailwind 4.3.3 and 3.4.19.
Input | Total | Identical | % |
|---|---|---|---|
JavaScript and TypeScript files | 13,952 | 13,654 | 97.9% |
HTML, Vue, Angular, LWC, Handlebars, CSS, SCSS, Less, Markdown and MDX files | 2,176 | 2,148 | 98.7% |
Tailwind 3 projects | 15 | 15 | 100% |
About half of the differences are intentional. In className={`header${open ? " active" : ""}`}, the plugin trims " active" to "active", so the element ends up with the class headeractive. bun fmt keeps the space.
For package.json, keys are sorted in the same order as the plugin and values are left untouched. Of 13,670 real-world package.json files, 13,644 (99.8%) are byte-for-byte identical to the output of Prettier 3.9.9 with the plugin. 20 differ only in values that Bun preserves, and the plugin throws on the other 6.
.svelte files are formatted by default, and the output matches prettier-plugin-svelte 4.1.1. With a Prettier config, they're formatted if the config lists the plugin. To skip them, set svelte = false in [fmt] or pass --no-svelte.
If your config uses a plugin that bun fmt doesn't support, like prettier-plugin-jsdoc, it prints an error naming the plugin, skips the files the plugin applies to and exits with code 2.
Where bun fmt intentionally differs from Prettier#
Prettier's output changes the meaning of the code for these inputs. bun fmt preserves it.
Input | Prettier 3.9.9 |
|
|---|---|---|
|
| Kept |
`x | b` in a CSS selector | `x |
| Dropped | Kept |
A | Lines joined, so the comment swallows the next line | Kept |
bun fmt --debug-check re-parses each file after formatting and fails if the meaning changed, like Prettier's --debug-check.
(节选)
原文:Bun Blog|Bun v1.4.4,2026-10-22


成为第一条评论!
Nobody's responded to this post yet. Add your thoughts and get the conversation going.