Best Code Formatting Tools 2026
TL;DR
Prettier for maximum ecosystem compatibility; Biome for speed and combined lint+format. Prettier (~45M weekly downloads) is the established standard — every editor supports it, every config works. Biome (~1.5M downloads, growing fast) is 10-35x faster, written in Rust, and combines formatting + linting in one tool. dprint (~200K) is the fastest formatter and most configurable but has the smallest ecosystem. For new projects in 2026, Biome is compelling; for existing projects, Prettier is the safe choice.
Key Takeaways
- Prettier: ~45M weekly downloads — universal adoption, 2-language support, every editor plugin
- Biome: ~1.5M downloads — 10-35x faster, Rust-based, lint + format combined
- dprint: ~200K downloads — fastest, WASM plugins, most configurable
- Biome — compatible with most Prettier configs via
biome migrate prettier - ESLint + Prettier — still common combo but Biome replaces both
Why Code Formatting Matters
Code formatting sounds trivial — it's just whitespace and quotes, right? In practice, unformatted code creates real friction on teams. Every code review gets polluted with style comments ("semicolons here", "wrong quote style", "trailing comma missing"). Merge conflicts multiply because developers format the same lines differently. The cognitive overhead of reading inconsistently-formatted code adds up over months.
Automated formatters solve this entirely. When a formatter runs on every save and every pre-commit, style becomes a non-issue. Reviews focus on logic. Diffs show only meaningful changes. New team members don't need to learn an informal style guide — the formatter enforces it automatically.
The main question in 2026 is which formatter to choose, not whether to use one.
Prettier (The Standard)
// .prettierrc — config
{
"semi": true,
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf",
"overrides": [
{
"files": "*.json",
"options": { "printWidth": 80 }
}
]
}
# .prettierignore
node_modules
dist
.next
.cache
coverage
*.min.js
# Prettier CLI commands
prettier --write "src/**/*.{ts,tsx,js,jsx,json,css,md}"
prettier --check "src/**/*.{ts,tsx}" # CI check (fails if not formatted)
prettier --write . # Format everything
# With package.json scripts
# "format": "prettier --write .",
# "format:check": "prettier --check ."
// package.json — Husky + lint-staged integration
{
"lint-staged": {
"*.{ts,tsx,js,jsx}": ["eslint --fix", "prettier --write"],
"*.{json,css,md}": ["prettier --write"]
}
}
Prettier formats over 20 languages including JavaScript, TypeScript, CSS, Markdown, HTML, GraphQL, and YAML. This breadth is why it remains dominant — one tool handles your entire codebase.
Biome (Speed + Lint)
// biome.json — combines ESLint + Prettier replacement
{
"$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
"organizeImports": { "enabled": true },
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100,
"lineEnding": "lf"
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "all",
"semicolons": "always",
"arrowParentheses": "always"
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedVariables": "error"
},
"style": {
"noNonNullAssertion": "warn"
},
"suspicious": {
"noExplicitAny": "warn"
}
}
},
"files": {
"ignore": ["node_modules", "dist", ".next", "coverage"]
}
}
# Biome commands
biome format --write . # Format all files
biome check --write . # Lint + format + organize imports
biome lint . # Lint only
biome ci . # CI check (no writes, fails on issues)
# Migrate from Prettier
biome migrate prettier --write # Import .prettierrc settings
# Speed comparison (same codebase):
# Prettier: 2.3s
# Biome: 0.07s (33x faster!)
# VS Code setup — install Biome extension
# .vscode/settings.json
{
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"[javascript]": { "editor.defaultFormatter": "biomejs.biome" },
"[typescript]": { "editor.defaultFormatter": "biomejs.biome" },
"[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome" }
}
Biome's key advantage is consolidation: instead of installing and configuring ESLint, Prettier, and their integration (eslint-config-prettier to disable ESLint rules that conflict with Prettier), you install one tool. Biome handles formatting and linting in a single pass with a single configuration file.
dprint (Fastest)
// dprint.json — plugin-based config
{
"incremental": true,
"typescript": {
"lineWidth": 100,
"indentWidth": 2,
"useTabs": false,
"singleQuotes": true,
"quoteStyle": "preferSingle",
"trailingCommas": "onlyMultiLine",
"semicolons": "always"
},
"json": {
"lineWidth": 80,
"indentWidth": 2
},
"markdown": {
"lineWidth": 80
},
"plugins": [
"https://plugins.dprint.dev/typescript-0.93.0.wasm",
"https://plugins.dprint.dev/json-0.19.4.wasm",
"https://plugins.dprint.dev/markdown-0.17.8.wasm",
"https://plugins.dprint.dev/toml-0.6.2.wasm"
]
}
# dprint commands
dprint fmt # Format all files
dprint check # Check without writing (CI)
dprint fmt --diff # Show what would change
# Speed: fastest formatter available
# Prettier: 2.3s | Biome: 0.07s | dprint: 0.04s
dprint's incremental mode is its most distinctive feature: it remembers which files it's formatted and only re-formats files that have changed since the last run. In a large monorepo, this means formatting runs in milliseconds even for codebases with thousands of files.
Speed Benchmark
| Tool | Format 1000 files | Language Support | Lint | Type-aware |
|---|---|---|---|---|
| Prettier | 2-5s | 20+ languages | ❌ | ❌ |
| Biome | 0.05-0.1s | JS/TS/JSON/CSS | ✅ | ❌ |
| dprint | 0.03-0.08s | Via plugins | ❌ | ❌ |
| ESLint + Prettier | 4-15s | JS/TS | ✅ | ✅ optional |
Pre-Commit Hook Setup
All three formatters integrate cleanly with Husky + lint-staged for pre-commit enforcement:
# Install Husky + lint-staged
npm install --save-dev husky lint-staged
npx husky install
npx husky add .husky/pre-commit "npx lint-staged"
// package.json — lint-staged config
// With Prettier:
{
"lint-staged": {
"*.{ts,tsx,js,jsx}": ["prettier --write", "eslint --fix"],
"*.{json,css,md,yaml}": ["prettier --write"]
}
}
// With Biome:
{
"lint-staged": {
"*.{ts,tsx,js,jsx,json,css}": ["biome check --apply --no-errors-on-unmatched"]
}
}
// With dprint:
{
"lint-staged": {
"*.{ts,tsx,js,jsx,json,md}": ["dprint fmt"]
}
}
CI Integration
# GitHub Actions — Prettier check
- name: Check formatting
run: npx prettier --check .
# GitHub Actions — Biome check (faster)
- name: Biome check
run: npx @biomejs/biome ci .
# biome ci exits non-zero if any formatting or lint issues found
# GitHub Actions — dprint check
- name: Check formatting
run: npx dprint check
Biome's ci command is the cleanest CI integration: it runs both linting and formatting in a single command, outputs structured error messages, and exits with a non-zero code on any issue. For teams using GitHub Actions, this reduces CI configuration from two separate steps (lint step + format step) to one.
Team Adoption Considerations
Prettier is the safest choice when onboarding teammates who may have different editors or setups. The VS Code extension is installed by 30M+ developers; JetBrains, Neovim, Emacs, Helix all have mature Prettier plugins. You can be confident that every developer on the team can get format-on-save working regardless of their editor.
Biome is newer and the editor extension ecosystem is still catching up. VS Code and IntelliJ have official extensions. Neovim has an LSP plugin. The coverage isn't as complete as Prettier's, which can create friction when a team member uses an unusual editor.
dprint has the smallest editor extension ecosystem. For teams where all developers use VS Code or JetBrains, this isn't an issue. For more diverse editor setups, dprint may require some developers to run formatting manually.
When to Choose
| Scenario | Pick |
|---|---|
| Established project, max compatibility | Prettier |
| New project, want speed + lint | Biome |
| Monorepo with huge file count | Biome or dprint |
| Need type-aware linting | ESLint (or Biome + ESLint for type checks) |
| Non-JS files (Go, Rust, Python) | Prettier (for JS) + lang-specific tools |
| Migrating from Prettier | Biome (biome migrate prettier) |
| CI speed is critical | Biome or dprint |
Migrating from Prettier to Biome
If your project already uses Prettier and you want to switch to Biome, the migration is straightforward — Biome provides a migration command that reads your existing Prettier config and converts it automatically.
# Install Biome
npm install --save-dev --save-exact @biomejs/biome
# Initialize Biome config
npx @biomejs/biome init
# Migrate your existing .prettierrc to biome.json
npx @biomejs/biome migrate prettier --write
# Migrate your existing .eslintrc to biome.json (if using ESLint)
npx @biomejs/biome migrate eslint --write
After migration, review the generated biome.json to verify all your formatting preferences carried over correctly. The most common configuration differences: Biome's trailingCommas option uses different values than Prettier ("all" maps to "all" in Biome, but "es5" maps to "es5"), and some Prettier plugins (for Svelte, Astro, or GraphQL) don't have Biome equivalents yet.
Once you've validated the config, remove the old tools:
npm uninstall prettier eslint eslint-config-prettier eslint-plugin-prettier
# Remove old config files
rm .prettierrc .prettierignore .eslintrc*
# Update package.json scripts
# "format": "biome format --write ."
# "lint": "biome lint ."
# "check": "biome check --write ."
Update your VS Code settings to use Biome as the default formatter and remove the Prettier extension recommendation from .vscode/extensions.json. The Biome VS Code extension (biomejs.biome) handles both formatting and linting, replacing both the Prettier and ESLint extensions.
One important gap: Biome does not format Markdown, YAML, TOML, or GraphQL files (as of 2026). If your project formats these with Prettier, you have two options: keep Prettier only for those file types alongside Biome, or accept that those files won't be auto-formatted by your new tool. Many teams keep a minimal Prettier config for non-JS/TS files only.
Advanced Configuration Patterns
Scoped Overrides
All three formatters support per-file or per-glob overrides, which is essential for monorepos or projects with mixed conventions:
// .prettierrc — override for specific directories
{
"semi": true,
"singleQuote": true,
"overrides": [
{
"files": ["packages/legacy/**"],
"options": { "singleQuote": false, "semi": false }
},
{
"files": "*.md",
"options": { "printWidth": 80, "proseWrap": "always" }
}
]
}
// biome.json — override for specific patterns
{
"formatter": { "lineWidth": 100 },
"overrides": [
{
"include": ["**/*.test.ts", "**/*.spec.ts"],
"linter": {
"rules": {
"suspicious": { "noExplicitAny": "off" }
}
}
},
{
"include": ["scripts/**"],
"formatter": { "lineWidth": 120 }
}
]
}
Editor Integration Without Extensions
For developers who prefer not to install editor extensions, both Prettier and Biome can be configured to run as a format-on-save command via your editor's shell command integration. This is useful in environments where the extension marketplace is restricted.
Disabling Formatting for Specific Code Blocks
Sometimes auto-formatting breaks intentional alignment or visual structure:
// Prettier — disable for a block
// prettier-ignore
const matrix = [
1, 0, 0,
0, 1, 0,
0, 0, 1,
];
// Biome — disable for a block
// biome-ignore format: intentional alignment
const matrix = [
1, 0, 0,
0, 1, 0,
0, 0, 1,
];
Use these sparingly — the more ignore comments you have, the more you're fighting the formatter. If you find yourself frequently disabling formatting for a pattern, it's worth adjusting your formatter config instead.
FAQ
Should I use eslint --fix alongside Prettier or Biome?
With Biome, you don't need both — Biome replaces both ESLint and Prettier. With Prettier, you still need ESLint for linting (Prettier only handles formatting), but you need eslint-config-prettier to disable ESLint's formatting rules and prevent conflicts. The Biome approach is simpler because there's no conflict to manage.
Does Prettier support TypeScript 5.x features?
Yes. Prettier's TypeScript parser is kept up to date with TypeScript releases. New TypeScript syntax (decorators, const type parameters, etc.) is supported in Prettier within a release or two of the TypeScript release. Biome and dprint are also updated quickly for new TypeScript syntax.
Why does Biome format slightly differently from Prettier even with the same settings?
Biome is not a Prettier clone — it makes some independent formatting decisions. The most noticeable difference is in how it handles long function calls and template literals. For most code, the output is identical or equivalent. For cases where they differ, biome migrate prettier maps the closest available option, but 100% identical output is not guaranteed. Evaluate on your actual codebase before committing to migration.
Can dprint format non-JavaScript files like CSS or YAML?
Yes, via plugins. dprint has a plugin architecture where each language is a separate WASM plugin. There are plugins for TypeScript, JavaScript, JSON, Markdown, TOML, and others. YAML and CSS plugins exist but are less mature than Prettier's equivalent support. For these file types, Prettier remains the safer choice.
What's the performance impact of running formatting in a pre-commit hook?
With Prettier on a large codebase, pre-commit hooks can take 5-10 seconds because lint-staged runs Prettier on all staged files. With Biome or dprint, the same operation typically completes in under a second. For teams with fast iteration cycles, this difference in pre-commit speed is noticeable and affects how often developers commit.
When NOT to Use a Formatter
Formatters solve real problems, but there are situations where they introduce more friction than they remove.
Generated code files. If your project generates code as part of its build process — GraphQL operation types, Prisma client files, protobuf outputs — adding those generated files to formatter coverage is counterproductive. The generator owns the style of its output. Mark these paths in .prettierignore or Biome's files.ignore array, and commit them as-is from the generator.
Files with intentional alignment. Lookup tables, ASCII art, structured comments, and some configuration files rely on visual alignment that formatters will destroy. Rather than fighting the formatter with // prettier-ignore on every block, consider whether these files belong in the formatter's scope at all. Place them in a subdirectory that your formatter ignores.
Projects in the final stages of a release. Introducing a formatter into a project right before a major release creates a massive diff that makes the release harder to review and increases the risk of accidental merge conflicts with long-running feature branches. The right time to adopt a formatter is at the start of a project or at the very beginning of a development cycle, when there are few or no active long-lived branches.
Projects with non-standard file types not supported by the formatter. If a significant portion of your codebase is in a language or file type your chosen formatter doesn't support (Svelte files with Biome, for example), you either end up with mixed formatting (some files auto-formatted, others not) or you add a second formatter to cover the gap. In these cases, a single formatter that covers all your file types — even if it's slower — may be preferable to managing two.
Formatting as Part of the Quality Pipeline
Formatting is one layer of a broader code quality system. Understanding how it fits alongside other tools helps you design a pipeline that catches issues at the right time without being slow or annoying.
The recommended layering for a TypeScript project in 2026:
At save (editor): Format the current file with your formatter. This gives immediate feedback and keeps files clean during development. All three formatters have reliable editor plugins for VS Code, IntelliJ, and most popular editors.
At commit (pre-commit hook via Husky + lint-staged): Run the formatter and linter on only staged files. This is the last line of defense before code enters the repository. By limiting to staged files, the hook completes in under a second even in large codebases.
In CI (GitHub Actions or equivalent): Run the formatter in check mode (prettier --check, biome ci) and the linter in check mode. This is authoritative — CI should fail if any file isn't formatted or any lint rule is violated. This catches cases where a developer committed without running the pre-commit hook.
At type checking (separate CI step or watch process): Run tsc --noEmit for TypeScript type checking. This is separate from formatting and linting because it's significantly slower (10-30 seconds for large projects vs under 1 second for formatting). It doesn't belong in the pre-commit hook for most teams — it slows commits too much and the IDE already shows type errors in real time.
The important thing is that each layer has a specific job. Formatters don't type-check; type checkers don't lint; linters don't format. Biome blurs the formatter/linter boundary (intentionally), but even with Biome you still need a separate type-checking step with tsc.
For teams adopting this pipeline from scratch, the recommended order of adoption is: formatter first (lowest friction, highest ROI), then linting, then type checking, then advanced static analysis. Each step builds on the last and reduces the noise-to-signal ratio for the next.
Compare formatter package health on PkgPulse. Also see our Vitest vs Jest comparison for the testing side of your quality toolchain and Biome vs ESLint + Prettier for a deeper linting comparison.
See the live comparison
View prettier vs. biome on PkgPulse →