auto-prettier
The reference PostToolUse hook for automatic Prettier formatting. 25 lines of bash, 3 lines of settings.json, and every JS/TS/CSS/HTML/JSON/MD/YAML file Claude writes lands formatted correctly — silently, using your project's own config.
PostToolUseWrite|Editauto-prettier is the poster child of the "install-once-forget-forever" hook category. Twenty-five lines of bash, three lines of settings.json, and from that moment on every JavaScript, TypeScript, CSS, HTML, JSON, Markdown, or YAML file Claude Code writes or edits comes out formatted correctly — without you asking, without slowing the interaction down, without leaving any drift for humans to clean up later.
The hook runs as a PostToolUse shell command matching Write|Edit. When Claude writes a matching file, the hook runs prettier --write, which reads your project's existing .prettierrc and formats accordingly. If Prettier succeeded, the operation continues silently. If Prettier couldn't format the file (syntax error, config problem), the error goes back to Claude so it can address it on the next turn — but the write still happens. That warn-vs-block discipline is what makes formatter hooks comfortable to install.
If you're on a JS/TS project and haven't installed this yet, do it before any other hook. It's the single highest install-to-value ratio in the whole hooks library.
The full auto-prettier hook
Two files: the bash script and the settings.json wiring. Both commit to git so every teammate gets the hook automatically.
And the settings.json wiring:
How to install
Four steps — save the script, make it executable, register in settings.json, restart Claude Code. Under five minutes end to end.
1. Save the script Step 1
Save the bash script to .claude/hooks/auto-prettier.sh at your repo root. Create the directory if it doesn't exist. Commit both to git so teammates get the hook on next pull.
2. Make executable Step 2
Run chmod +x .claude/hooks/auto-prettier.sh. Claude Code executes the file directly, so non-executable scripts silently fail. This is the single most common install mistake.
3. Register in settings.json Step 3
Add the JSON snippet above to .claude/settings.json. Use $CLAUDE_PROJECT_DIR in the path so the hook works for teammates whose repo lives at a different absolute path.
4. Verify Step 4
Restart Claude Code. Ask it to write any TypeScript file, then check whether it comes out formatted. If not, check chmod, matcher pattern (case-sensitive: Write|Edit), and file path in settings.json.
How to use it
There's no manual invocation — the hook fires automatically. These are the interactions where you'll notice it working.
Edit path. Claude edits the file, the hook runs Prettier on the edited file. Same behavior, same silent success.config.js to config.ts and rewrites content, the hook fires on the write and formats the new file. Renames+edits work transparently..prettierignore natively. Files in your ignore list get skipped automatically. No extra config in the hook needed.Alternative configs
Adjust the hook for specific project needs.
npx --no-install eslint --fix "$file_path". Same warn-on-failure discipline. Runs after Prettier so ESLint's auto-fixes don't get reformatted away." Or install the separate auto-eslint hook for clean separation.PostToolUse hook that runs tsc --noEmit scoped to the affected package. Warns on type errors so Claude can fix them next turn. See auto-typecheck for the full setup.npx prettier call to cd "$(dirname "$file_path")" && npx --no-install prettier --write "$file_path". This runs Prettier from the closest config — important in Turborepo/Nx setups where each package has its own Prettier config.Pairs well with
Formatter hooks compose cleanly. Most JS/TS projects install three or four of these together.
eslint --fix after Prettier. Auto-fixes what it can, warns about the rest. Natural pair.tsc --noEmit on the affected package. Catches type errors before they compound. Adds ~500ms but worth it on typed projects.Common issues and fixes
The five issues teams hit most often installing this hook.
chmod +x .claude/hooks/auto-prettier.sh. Confirm the matcher in settings.json is exactly Write|Edit (case-sensitive, no spaces). Test by asking Claude to write any TS file and checking whether the file lands formatted.prettier in node_modules), or the file extension isn't in the matched list.pnpm add -D prettier (or npm install). Check the file extension is in the script's regex — add it if needed (e.g., vue, svelte). The --no-install flag in the script prevents npx from silently installing the wrong version..turbo, storybook-static, etc. as needed). If large files are legitimately slow, consider Prettier's cache: npx prettier --write --cache speeds up repeat runs significantly.exit 2 (block) if you want strict enforcement — but this is aggressive; most teams stick with warn.package.json ("prettier": "3.4.2", not ^3). Both the hook and git pre-commit will use the same binary. Zero drift, zero cleanup PRs.Other formatter items
Same category, different job.
🐛 Hit an error?
AI Error Hub covers Claude Code errors and stack traces — cross-referenced with everything on this site.
Frequently asked questions
The questions developers ask most about auto-prettier.
Blocking on formatter failure means every syntax error becomes a wall Claude can't get past on the current turn. Warning lets Claude see the error message and fix it on the next turn — the actual desired behavior.
Reserve block-level severity (exit 2) for security hooks and destructive-operation gates. For formatters, warn (exit 1) is right.
Not meaningfully. Prettier on a single file runs in about 100ms.
For a session with 30 file edits that's 3 seconds of total added latency across the whole session — imperceptible in interactive use.
The exception is very large generated files, which is why the script excludes node_modules, dist, build, and other generated directories.
The hook exits 0 silently with a stderr note. That's intentional — you don't want the hook to punish an interaction because a teammate hasn't run pnpm install yet, or because Prettier isn't a dev dependency in that repo.
The "prettier not installed; skipping format" log leaves a paper trail so someone eventually adds it.
Yes — the hook invokes Prettier's own CLI, which reads .prettierignore natively. No extra config in the hook needed.
The hook's own skip list (node_modules, .next, dist, etc.) is a defense-in-depth optimization that avoids even shelling out for known-ignored paths — faster than letting Prettier read and then ignore them.
Yes, and it's common on JS/TS projects. auto-prettier + auto-eslint + auto-typecheck all run on TypeScript writes.
They execute in the order declared in settings.json. Just watch total latency — three formatters running on every write can add up.
In monorepos, keep the typecheck one scoped to the affected package to avoid the slowest hook running project-wide.
No. Hooks fire on tool-use events regardless of who invoked the tool. When a subagent writes a file, the PostToolUse auto-prettier hook runs just as it would in the main conversation.
This is important — team-shared formatters must apply uniformly. If nextjs-15-expert or postgres-dba writes a file, it still gets formatted.
Complementary layers:
- Editor plugin — formats when a human saves in the editor.
- auto-prettier hook — formats when Claude Code writes via its tools.
- Git pre-commit — catches anything reaching commit stage from either source.
Best practice: all three. Layers, not silver bullets.
Adapt the script — swap npx prettier --write for biome format --write or dprint fmt. The rest of the script (path filtering, exit-code discipline, generated-dir exclusion) works identically.
If you'd rather not maintain the script yourself, the Repo Analyzer tool detects Biome/dprint and generates a matching hook.
Yes, absolutely. Commit .claude/settings.json and .claude/hooks/ together — every teammate gets the same setup on next pull.
This is exactly the pattern that makes Claude Code output indistinguishable from human output. No drift, no version-skew debates, no cleanup PRs.
Yes — the hook invokes your project's Prettier install, which reads .prettierrc and loads any plugins listed there.
If you have @prettier/plugin-tailwindcss or prettier-plugin-organize-imports configured, they apply on every Claude write automatically. No changes to the hook needed.
Get the weekly Claude Code digest
Every Tuesday: new formatter, Anthropic release recap, and the best community submission. 13,000+ developers read it.