Inconsistent code style is a silent productivity killer. Every manual format pass before a commit, every "nit: indentation" comment in a PR, every diff polluted by whitespace-only lines — all of it disappears the moment you enable vs code format on save. One setting, and the editor handles style automatically every time you hit Ctrl+S. This guide covers the complete setup: enabling vscode auto format on save, choosing between Prettier and the built-in formatter, configuring per-language rules, resolving ESLint conflicts, and — a workflow no other guide covers — using a diff tool to verify a formatter changed only whitespace, not logic. If you want to level up adjacent VS Code habits alongside this one, see how to compare two files in VS Code and how multi-cursor editing pairs naturally with bulk reformatting. For a broader look at automated code quality tools that complement format-on-save, our overview of static code analysis tools is worth a read.
What Format on Save Actually Does
When you press Ctrl+S (or Cmd+S on macOS), VS Code normally just
writes the file to disk. With editor.formatOnSave enabled, it first runs the
active formatter against the entire file, applies the changes to the buffer, then saves.
The round-trip is typically imperceptible — under 100 ms for most files.
What the formatter actually changes depends on which formatter you have selected, but common transformations include:
- Indentation — normalizes tabs vs spaces and depth (2 or 4 spaces)
- Quotes — enforces single or double quotes consistently
- Semicolons — adds or removes them based on your rule set
- Trailing commas — inserts them on multi-line structures
- Print width / line wrapping — breaks long lines at a configured column
- Blank line normalization — removes extra blank lines, enforces spacing between blocks
- Bracket spacing — adds or removes spaces inside
{and}
Crucially, a correctly configured formatter touches only whitespace and stylistic tokens — it never changes logic. That claim is verifiable, and we will show you exactly how to verify it with a diff later in this guide.
The practical upside extends beyond aesthetics. Consistent formatting means git diffs show only real changes, code reviews focus on logic instead of style, and new contributors cannot accidentally commit differently-formatted files. According to the VS Code documentation on code basics, formatting is one of the most commonly configured editor behaviors.
Quick Setup: Enable Format on Save in 60 Seconds
The fastest path to working vscode auto format on save:
- Open the Command Palette (Ctrl+Shift+P / Cmd+Shift+P), type Open User Settings JSON, and press Enter.
-
Add these two lines inside the top-level object:
"editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" - Save the file (Ctrl+S). The setting takes effect immediately.
- Open any JavaScript or TypeScript file, introduce some messy spacing, and save it. VS Code formats the file before writing it to disk.
If you do not have Prettier installed yet, open the Extensions panel
(Ctrl+Shift+X), search for Prettier - Code formatter
(publisher: Esben Petersen, ID: esbenp.prettier-vscode), and install it.
Alternatively, if you prefer the VS Code built-in formatter, set
"editor.defaultFormatter": "vscode.typescript-language-features" for JS/TS
files, or simply omit the line — VS Code will fall back to the built-in formatter when
no default is set.
The Settings UI route
If you prefer the GUI: open Settings (Ctrl+,), search for
format on save, and check the Editor: Format On Save checkbox.
To pick a formatter, search for default formatter and choose from the
dropdown. Both routes write to the same settings.json file.
Choosing a Formatter: Prettier vs VS Code Built-in
The most important decision before enabling format on save is which formatter to use. Getting this wrong means either no formatting (if the formatter is missing) or unexpected results (if two formatters fight each other).
prettier --check The VS Code built-in formatter handles JavaScript, TypeScript, JSON, HTML,
and CSS. It is fast and requires no extension, but it has limited configurability — you
control indentation size and a handful of other options through settings.json,
but not trailing commas, print width, or bracket spacing.
Prettier is the industry standard for JavaScript-ecosystem projects. The
Prettier documentation
shows it supports over 20 languages including TypeScript, JSX, TSX, HTML, CSS, SCSS, Less,
JSON, GraphQL, Markdown, and YAML. Its key advantage is the .prettierrc config
file: commit it to your repo and every team member and CI run uses identical rules,
eliminating "formatting drift" across machines.
A minimal .prettierrc to pin the most commonly debated options:
{
"semi": true,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100
} Drop that file in the project root and Prettier uses it automatically. No arguments needed on the command line or in the VS Code extension.
Global vs Workspace Settings
VS Code applies settings in a layered hierarchy. Understanding which layer controls format on save is critical — many "format on save not working" reports come from a workspace override silently overriding a user-level setting.
| Scope | File Location | When to Use |
|---|---|---|
| User (global) | ~/.config/Code/User/settings.json (Linux) or ~/Library/Application Support/Code/User/settings.json (macOS) | Personal defaults that apply everywhere — all projects on your machine |
| Workspace | .vscode/settings.json in the project root | Project-specific overrides — committed to the repo so everyone on the team gets the same behavior |
| Folder | Per-folder settings in a multi-root workspace | Monorepos where sub-packages need different formatters |
Workspace settings override user settings. If your user settings have
"editor.formatOnSave": true but a project's .vscode/settings.json
has "editor.formatOnSave": false, format on save is disabled in that project.
The VS Code status bar shows the active scope — look for the gear icon in the bottom-right
when Settings is open.
Recommendation for teams: commit a .vscode/settings.json that
sets "editor.formatOnSave": true and "editor.defaultFormatter" to
your chosen formatter. This ensures every contributor gets format on save, regardless of
their personal preferences, and eliminates whitespace-only commits from people who have
different global settings.
// .vscode/settings.json (commit this to the repo)
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
} Per-Language Format on Save Configuration
A single global editor.formatOnSave applies to every file type. Sometimes you
want different behavior per language — for example, format Python but not Markdown, or use
a different formatter for Go than for JavaScript. VS Code supports language-specific
settings via the [languageId] override syntax in settings.json.
{
// Global default: format everything
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
// JavaScript/TypeScript: Prettier
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// Python: Black (ms-python.black-formatter)
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true
},
// Go: built-in gopls formatter
"[go]": {
"editor.defaultFormatter": "golang.go",
"editor.formatOnSave": true
},
// Markdown: disable format on save (too aggressive)
"[markdown]": {
"editor.formatOnSave": false
}
}
The language identifier comes from the language mode shown in the VS Code status bar
(bottom-right). Click it on any open file to see its ID — for example,
javascriptreact for JSX, typescriptreact for TSX,
shellscript for Bash.
Python: Black vs autopep8
Python has two popular formatters. Black (ms-python.black-formatter) is
opinionated and uncompromising — it makes decisions for you and produces consistent output
with no configuration. autopep8 (ms-python.autopep8) is gentler and stays
closer to the original code structure. For new projects, Black is the current community
preference. Set "editor.defaultFormatter": "ms-python.black-formatter" in the
[python] block.
Go: gofmt is non-negotiable
Go enforces formatting through gofmt, which ships with the language. The
VS Code Go extension (golang.go) hooks into it. With
"editor.formatOnSave": true in the [go] block, every file is
gofmt-formatted on save. There is no meaningful choice here — Go's ecosystem mandates
it and goimports (which also organizes imports) is the extended version.
Rust: rustfmt
The rust-analyzer extension (rust-lang.rust-analyzer) includes rustfmt support. Add a
[rust] block with
"editor.defaultFormatter": "rust-lang.rust-analyzer" and format on save works
identically to Go.
ESLint + Prettier Without Conflicts
Running ESLint and Prettier together is the most common source of format-on-save headaches. ESLint enforces code quality rules; Prettier enforces code style. When they overlap on stylistic rules — like semicolons or quote style — they can fight each other, with Prettier formatting one way and ESLint immediately flagging it as wrong.
The standard solution is two packages:
-
eslint-config-prettier— turns off all ESLint rules that would conflict with Prettier. Install withnpm install --save-dev eslint-config-prettierand add"prettier"as the last item in your ESLintextendsarray. -
eslint-plugin-prettier(optional) — runs Prettier as an ESLint rule, surfacing Prettier violations as ESLint errors. Useful for CI but adds overhead in the editor.
The cleanest VS Code setup for ESLint + Prettier uses two separate tools for two
separate concerns: Prettier handles formatting on save, ESLint handles code quality on
save via editor.codeActionsOnSave:
{
// Prettier formats the file on save
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
// ESLint fixes auto-fixable lint errors on save
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
With this setup, saving a file triggers two passes: Prettier reformats style, then
ESLint auto-fixes any fixable code-quality issues. Neither tool touches the other's
domain — as long as eslint-config-prettier is installed and extends your
ESLint config.
editor.formatOnSave before
editor.codeActionsOnSave. Prettier runs first, then ESLint's auto-fix pass.
This order is correct — formatting first, then linting, prevents the two from fighting.
Using a vscode beautifier: Formatters Compared
The term vscode beautifier often refers to any code formatting extension for VS Code, not just one specific tool. The original "Beautify" extension (HookyQR.beautify) was popular in earlier VS Code versions but has been largely superseded by more modern options. Here is a current map of formatters by language:
| Language | Recommended Formatter | Extension ID | Config File |
|---|---|---|---|
| JS / TS / JSX / TSX | Prettier | esbenp.prettier-vscode | .prettierrc |
| CSS / SCSS / Less | Prettier | esbenp.prettier-vscode | .prettierrc |
| HTML | Prettier or built-in | esbenp.prettier-vscode | .prettierrc |
| Python | Black | ms-python.black-formatter | pyproject.toml |
| Go | gofmt / goimports | golang.go | gofmt (no config) |
| Rust | rustfmt | rust-lang.rust-analyzer | rustfmt.toml |
| Java | Language Support for Java | redhat.java | .editorconfig |
| C / C++ | clang-format | ms-vscode.cpptools | .clang-format |
| JSON | Prettier or built-in | esbenp.prettier-vscode | .prettierrc |
| YAML | Prettier | esbenp.prettier-vscode | .prettierrc |
EditorConfig (.editorconfig) is not a formatter — it is a
cross-editor configuration standard that normalizes indentation, end-of-line characters, and
charset. VS Code respects .editorconfig files natively. It works
alongside Prettier, not instead of it: EditorConfig handles the basic file-level
settings, Prettier handles the deeper stylistic choices. If both exist in a project, Prettier
takes precedence on any option it covers.
The old HookyQR Beautify extension is still available on the marketplace but is no longer actively maintained and does not support modern JavaScript syntax (ESM, optional chaining, nullish coalescing). Uninstall it if you see unexpected behavior — it may be intercepting save events before Prettier gets to run. Checking for this is a good first step in finding the difference between what you expect and what your editor actually does.
Verify Formatting With a Diff
Here is a workflow no other formatter guide covers: verifying that a formatter changed only whitespace, not logic. This matters in two scenarios:
- You just enabled format on save on a legacy codebase and want to confirm the first formatting pass did not corrupt any strings, template literals, or ASI-sensitive semicolon placements.
-
You updated Prettier from v2 to v3 (or changed
.prettierrcrules) and want to audit what changed before committing the reformatted files.
The format → diff workflow
- Copy the file content before saving. Open the file, select all (Ctrl+A), copy (Ctrl+C). This is your "before" state.
- Save to trigger format on save. Press Ctrl+S. VS Code formats and writes the file.
- Copy the formatted content. Select all again and copy the reformatted code. This is your "after" state.
- Open Diff Checker and paste both versions. The Diff Checker Chrome extension — built on Monaco Editor (the same engine that powers VS Code) — lets you paste the before version on the left and the after version on the right, then run a diff instantly in your browser. No file uploads, 100% local.
- Switch to "Ignore Whitespace" diff mode. Diff Checker includes three diff algorithms: Smart, Classic (LCS), and Ignore Whitespace. Select "Ignore Whitespace" and click Run Diff again. If the diff now shows zero changes, the formatter touched only whitespace — your logic is intact.
This workflow is especially useful when onboarding Prettier onto a large existing codebase. Run it on a representative sample of files before committing all the reformatted code. If the "Ignore Whitespace" diff shows changes, something unexpected happened — perhaps a template literal or a regex that Prettier re-arranged.
Diff Checker also has a Format Code button powered by Prettier, supporting the same 20+ languages as the VS Code extension. If you want to preview what Prettier would do to a snippet without saving a file, paste the code into Diff Checker, click Format Code, and compare the before/after directly in the split view. It is a quick sanity check for one-off questions like "what will Prettier do to this JSX?"
Another use case: after running collapse all regions in a large file (see our
guide on VS Code collapse all),
you can quickly scan the formatted output at a high level, then use the diff view to
confirm what changed between versions.
Troubleshooting: Format on Save Not Working
Problem: "There are multiple formatters" warning
A yellow notification appears in VS Code: "There are multiple formatters for [language].
Select a default formatter to continue." This happens when two or more extensions both
register as formatters for the same language ID. The fix is explicit: add
"editor.defaultFormatter" to your settings, either globally or in the
appropriate language-specific block. VS Code shows the formatter IDs in the dropdown that
appears when you click the notification.
Problem: Prettier not detecting .prettierrc
Prettier searches for config files by walking up the directory tree from the file being
formatted. If your .prettierrc is not in the project root or any parent
directory of the open file, Prettier falls back to defaults. Common causes:
- You opened VS Code on a subdirectory inside a monorepo instead of the root.
- The
.prettierrcfile has a typo in the name (it's case-sensitive on Linux). - The Prettier version installed globally differs from the one in
node_modules— install locally withnpm install --save-dev prettierand the VS Code extension will prefer the local version.
Problem: Format on save is too slow
For very large files (>10,000 lines), formatting can take noticeable time. Options:
-
Set
"editor.formatOnSaveMode": "modificationsIfAvailable"— this formats only the lines you actually changed (when git diff info is available), not the whole file. Significantly faster on large files. -
Add large auto-generated files (build output,
dist/, compiled CSS) to.prettierignoreso Prettier skips them entirely.
Problem: ESLint and Prettier both running but conflicting
If you see Prettier format a file one way but ESLint immediately flags style errors in
the same file, eslint-config-prettier is either not installed or not placed
last in your ESLint extends array. The last item in extends wins.
The correct order is:
// eslint.config.js (ESLint v9 flat config)
import eslint from "@eslint/js";
import prettier from "eslint-config-prettier";
export default [
eslint.configs.recommended,
// ... your other configs ...
prettier, // must be last — disables ESLint style rules that conflict
]; Problem: File saves without formatting (one-off bypass)
Sometimes you need to save a file without triggering the formatter — for example, saving
mid-edit when the code is intentionally incomplete. Use
File: Save without Formatting from the Command Palette, or bind it to a
key. There is no default keybinding — add one to keybindings.json:
{
"key": "ctrl+k s",
"command": "workbench.action.files.saveWithoutFormatting"
} How to Turn Off Format on Save
Three scenarios where disabling makes sense: you are working on a project with no style conventions, you are in a quick debug session and formatting noise is distracting, or you are editing an auto-generated file you do not want reformatted.
Globally
// User settings.json
"editor.formatOnSave": false Per workspace
// .vscode/settings.json
"editor.formatOnSave": false Per language
// Disable only for Markdown, keep for everything else
"[markdown]": {
"editor.formatOnSave": false
} One-off save without formatting
Use the Command Palette → File: Save without Formatting. This is a single-use bypass — the next Ctrl+S goes back to normal format-on-save behavior. It is the cleanest way to handle the occasional "I just need to save this draft" case without permanently changing settings.
After disabling, you can still format manually at any time with the keyboard shortcut Shift+Alt+F (Windows/Linux) or Shift+Option+F (macOS), or via the Command Palette → Format Document. See the VS Code formatting documentation for the full list of formatting commands and their keybindings.
For teams where individual contributors have different habits, the best practice is to
enforce formatting at the CI level (using prettier --check . in a pre-push hook
or CI job) rather than relying solely on editor settings. That way the repo stays clean
regardless of what any individual developer has in their local settings.json.
This is the same category of static enforcement covered by
static code analysis tools — format
checking is a lightweight form of static analysis.
Frequently Asked Questions
- How do I auto-format on save in VS Code?
-
Add
"editor.formatOnSave": trueto yoursettings.jsonto enable vs code format on save. If multiple formatters are installed for the same language, also add"editor.defaultFormatter": "extension.id"— for example"esbenp.prettier-vscode". For team projects, commit a.vscode/settings.jsonwith both lines so everyone gets the same vscode auto format on save behavior automatically. - What is the best formatter for VS Code?
-
For JavaScript, TypeScript, CSS, HTML, and JSON: Prettier
(
esbenp.prettier-vscode). For Python: Black (ms-python.black-formatter). For Go: the official Go extension (golang.go) which uses gofmt. For Rust: rust-analyzer (rust-lang.rust-analyzer). For multi-language projects, Prettier covers the most ground with a single.prettierrcconfig file. - Why is my formatter not working in VS Code?
-
Check in this order: (1) Is
"editor.formatOnSave": true? (2) Is"editor.defaultFormatter"set and the extension installed? (3) Is a workspace.vscode/settings.jsonoverriding your user settings with"editor.formatOnSave": false? (4) Open the Output panel (Ctrl+Shift+U) and select your formatter from the dropdown — error messages appear there. (5) Try reloading the window (Ctrl+Shift+P → Reload Window). - Does VS Code have a built-in formatter?
-
Yes. VS Code ships with built-in formatters for JavaScript, TypeScript, JSON, HTML, and
CSS that handle basic indentation, semicolons, and quote style — no extension required.
For more opinionated formatting (trailing commas, print width, bracket spacing) you need
an extension like Prettier. The built-in formatter is identified as
vscode.typescript-language-featuresin theeditor.defaultFormattersetting. - How do I turn off format on save?
-
Set
"editor.formatOnSave": falsein your user settings (global) or in.vscode/settings.json(workspace). To disable it for a single language only, use a language-specific block — for example[markdown]with"editor.formatOnSave": false. To skip formatting on a one-off save, run File: Save without Formatting from the Command Palette.
Enabled format on save and want to verify the formatter only touched whitespace? Paste the before and after versions of your file into Diff Checker, switch to "Ignore Whitespace" mode, and confirm zero logic changes — all locally, no uploads. Diff Checker also includes a Format Code button (Prettier, 20+ languages) so you can preview exactly what Prettier will do to any snippet before committing.
Install Diff Checker — Free Chrome Extension