Migrate from Prettier to bun fmt

bun fmt reads your .prettierrc and prints what Prettier 3 prints. In most projects you only change the command.

Start with --doctor. It shows what Bun will do with your config, and it doesn't format or write anything.

terminal
bun fmt --doctor
Using .prettierrc (Prettier config)

    4 files are formatted natively

Built-in plugins: @ianvs/prettier-plugin-sort-imports

You can remove: @ianvs/prettier-plugin-sort-imports
Still needed:   prettier (the "format" script runs it)
Not checked:    other tools' configs, CI files, Git hooks

Change the scripts.

package.json
{
  "scripts": {
    "format": "prettier --write .", 
    "format:check": "prettier --check .", 
    "format": "bun fmt", 
    "format:check": "bun fmt --check" 
  }
}

bun fmt writes by default and formats the current directory, so --write . goes away. Other flags and arguments stay the same. Change CI and Git hooks too.

If your script is called fmt, don't skip this: bun fmt runs a fmt script when package.json has one, so you'd still get Prettier.

Watch out for two differences in hooks and shell scripts:

  • No arguments means the current directory. Prettier prints an error there. So if the file list can be empty, as in git diff --cached --name-only | xargs bun fmt or bun fmt $(git ls-files '*.foo'), Bun formats everything. Use bun fmt --staged in a pre-commit hook, or xargs -r.
  • bun fmt file.ts writes the file and prints its name. prettier file.ts prints the formatted code. To print it, pipe the code in: bun fmt --stdin-filepath file.ts < file.ts.

Piping into --parser works like in Prettier: generate | bun fmt --parser typescript > out.ts.


Check that nothing changes. With a Prettier config, --check prints what Prettier prints.

terminal
bun fmt --check
$ bun fmt --check
Checking formatting...
All matched files use Prettier code style!

Run --doctor again. No script runs Prettier anymore, so it can go too.

You can remove: @ianvs/prettier-plugin-sort-imports, prettier
Not checked:    other tools' configs, CI files, Git hooks
terminal
bun remove prettier @ianvs/prettier-plugin-sort-imports

Leave .prettierrc as it is, including plugins.

Keep prettier if your editor's Prettier extension uses it.


Bun reads everything Prettier reads:

  • .prettierrc in JSON, YAML, TOML, JavaScript, or TypeScript, prettier.config.*, and "prettier" in package.json, with overrides
  • .editorconfig, .prettierignore, and .gitignore
  • // prettier-ignore comments and the @format and @noformat pragmas
  • Every flag of Prettier 3 except --file-info and --support-info

Bun doesn't load Prettier plugins. These are built in, with all their options, so leave them in plugins:

  • prettier-plugin-tailwindcss
  • @trivago/prettier-plugin-sort-imports
  • @ianvs/prettier-plugin-sort-imports
  • prettier-plugin-organize-imports
  • @prettier/plugin-oxc

Svelte, Astro, and other languages that come from a plugin go to your installed Prettier. So does package.json if you use prettier-plugin-packagejson. Keep prettier and every plugin in plugins installed. --doctor shows which files those are.

Using .prettierrc (Prettier config)

    3 files are formatted natively
    1 file goes to your installed Prettier: 1 *.svelte

Built-in plugins: @ianvs/prettier-plugin-sort-imports
Plugins that use your installed Prettier: prettier-plugin-svelte

Still needed:   @ianvs/prettier-plugin-sort-imports, prettier, prettier-plugin-svelte (some files go to them)

With any other plugin, Bun skips the files that config covers and exits with code 2. A plugin could print them differently, and Bun won't guess. Pass --allow-unsupported to format them without the plugin.

[error] 3 files were not formatted because the Prettier config uses plugins that bun fmt does not include: prettier-plugin-brace-style
[error]   Use --allow-unsupported to format them without the plugins.

You don't have to keep .prettierrc. Move the options to bunfig.toml, under the same names, and delete the file. overrides become [[fmt.overrides]].

bunfig.toml
[fmt]
semi = false
singleQuote = true

Without a Prettier config, bun fmt also formats TOML files, and --check prints a shorter report.


Differences from Prettier#

If bun fmt and Prettier 3 print different code, that's a bug. Open an issue. These differences are intentional:

  • It writes by default. --write is accepted and does nothing.
  • No arguments means the current directory.
  • Only changed files are listed, followed by a summary on stderr.
  • An unknown flag is an error. Prettier warns and continues.
  • --cache does nothing. Every run formats every file.
  • Exit code 2 means something went wrong, like a syntax error or a skipped file. Prettier uses 1 for some of these.
  • Bytes that aren't valid UTF-8 are kept. Prettier replaces them.
  • Where Prettier's output changes what a file means, Bun's differs. That's rare. In a Handlebars template Prettier drops <!DOCTYPE html>, and it joins the lines of a <script>, so a // comment swallows the code after it. In CSS it turns Font\ Awesome into Font\Awesome. Bun keeps all three.
  • Symlinks that lead out of the repository aren't written through.
  • console.log in your config file is hidden unless the config fails to load.

See also: