← LearnClaude Code · Automation

Claude Code Automatic Formatting Hooks: Complete Workflow Guide

Claude Code hooks let you run a formatter like Prettier or gofmt automatically after every file edit using a PostToolUse hook — no prompt instructions needed. Configure hooks via the /hooks command or by editing your settings JSON file, and formatting runs deterministically every time.

What Are Claude Code Hooks and Why Do They Matter for Formatting?

Claude Code hooks are user-defined shell commands that execute automatically at specific points in Claude Code's lifecycle. Unlike asking Claude to run a formatter in your prompt, hooks guarantee deterministic behavior — they always run regardless of what the model decides. This makes them the right tool for enforcing consistent code style across every file Claude touches.

For automatic formatting specifically, the key hook event is PostToolUse, which fires after Claude completes a file write or edit. You attach a formatter command to that event, and from that point on, every file Claude modifies gets formatted immediately — without any prompt instructions, reminders, or reliance on Claude's judgment.

Learn more in the official Claude Code hooks reference.

How Do Claude Code Hooks Work Under the Hood?

Each hook is a JSON object stored in Claude Code's settings files. A hook definition specifies three things:

  • A trigger event — such as PreToolUse, PostToolUse, SessionStart, or Notification
  • An optional matcher pattern — to filter which tools trigger the hook (e.g., only fire on Edit, MultiEdit, or Write tools)
  • A handler command — the shell command, HTTP request, MCP tool call, or prompt-based evaluation to execute

When a hook fires, Claude Code passes contextual data to the hook via stdin as JSON — including the tool name and its inputs. The hook can then communicate back via exit codes and stdout/stderr output. A hook can silently allow an action, block it with an explanatory message, or inject additional context into Claude's next turn.

For a formatting workflow, the flow looks like this: Claude writes a file → PostToolUse hook fires → your formatter runs on that file → the formatted version is what ends up on disk. Claude never needs to know this happened.

How Do You Set Up Automatic Formatting Hooks in Claude Code?

There are two ways to configure hooks: through the interactive /hooks slash command inside Claude Code, or by directly editing the JSON settings file. Here is the complete workflow for both approaches.

Method 1: Using the /hooks Command (Recommended for Beginners)

  1. Install Claude Code and ensure you are on a supported plan (Pro, Max, Team, or Enterprise).
  2. Open your terminal and start a Claude Code session.
  3. Run the /hooks slash command inside Claude Code to open the interactive hooks configuration interface.
  4. Select the PostToolUse event.
  5. Choose whether to store the hook in User settings (applies to all projects) or Project settings (applies only to the current project).
  6. Enter your formatter command and save. Changes made via /hooks apply to new sessions automatically.

Method 2: Editing the Settings File Directly

  1. For user-level hooks, edit ~/.claude/settings.json. For project-level hooks, edit .claude/settings.json in your project root.
  2. Add your hook definition under the hooks key following the required JSON schema: event name → array of matcher and hooks objects.
  3. Restart your Claude Code session for any direct file edits to take effect. Claude Code does not hot-reload hook configurations during an active session — this is a deliberate security measure against malicious hook injection.

What Does a Real Automatic Formatting Hook Look Like?

The source material provides a concrete intermediate-level example for automatically formatting TypeScript files with Prettier after every edit. Here is how it works:

You add a PostToolUse hook to your project's settings with a matcher targeting the Edit, MultiEdit, and Write tools. The hook command checks whether the edited file has a .ts extension, and if so, runs Prettier on it.

Sample input the hook receives via stdin:

{
  "tool_name": "Write",
  "tool_input": {
    "file_path": "src/utils.ts",
    "content": "export const foo = (x:number)=>x+1"
  }
}

What happens: After Claude writes the file, Prettier runs on src/utils.ts and reformats it. The hook exits with code 0. The formatted version is what ends up on disk — not the unformatted version Claude originally wrote.

The same pattern works for any formatter: gofmt for Go files, black for Python, rustfmt for Rust. You adjust the file extension check and the formatter command.

See the getting started with Claude Code hooks guide for more worked examples.

When Should You Use Hooks vs. Other Approaches?

Approach Best For Limitation
PostToolUse hook Mandatory, unconditional formatting after every edit — guaranteed to run Cannot reverse or undo the tool action; runs after the fact
System prompt instruction Influencing Claude's behavior probabilistically (e.g., "prefer formatted output") Not guaranteed — Claude may not follow instructions in every case
Asking Claude in the prompt Context-dependent follow-ups that require judgment or should only happen sometimes Adds tokens, requires Claude to remember, not deterministic
PreToolUse hook Blocking or validating actions before they execute Cannot run a formatter here — the file hasn't been written yet

The bottom line: if you want formatting to happen every single time without exception, a PostToolUse hook is the right tool. System prompt instructions and direct prompting are better when the behavior should be conditional or context-sensitive.

What Are the Most Common Pitfalls When Setting Up Formatting Hooks?

Several mistakes trip up developers new to Claude Code hooks. Here are the ones most relevant to formatting workflows:

Not Restarting After Editing Settings Files

If you edit ~/.claude/settings.json or .claude/settings.json directly, Claude Code will not pick up the changes during an active session. Always restart your Claude Code session after direct file edits. Changes made through the /hooks interface apply to new sessions automatically.

Trying to Use PostToolUse to Undo Actions

PostToolUse hooks run after the tool has already executed. They cannot reverse file writes or other side effects. For formatting, this is fine — you want to reformat the file that was just written. But if you need to prevent something, use a PreToolUse hook instead.

Mixing Exit Codes and JSON stdout Output

Choose exactly one communication strategy per hook: either use exit codes with a plain stderr message, or exit 0 with a valid JSON object on stdout for structured control. When you exit with code 2 to block an action, Claude Code ignores any JSON on stdout entirely. For a formatting hook that should always allow the action, exit 0 and send any debug output to stderr, not stdout.

Printing Debug Output to stdout

If your hook command prints arbitrary text to stdout when Claude Code expects JSON, the internal parser will fail or ignore the output. All debug and informational output must go to stderr. Only valid JSON matching the expected schema should go to stdout.

Long-Running Formatters Blocking the UI

By default, hooks run synchronously and Claude Code waits for them to complete. For most formatters like Prettier or gofmt, this is fine — they're fast. But if your formatting step involves compilation or other slow operations, add "async": true to the hook definition so it runs in the background and injects results as context on the next turn rather than blocking immediately.

What Other Workflows Can Hooks Power Beyond Formatting?

Once you understand the formatting hook pattern, the same mechanism unlocks a range of other automation scenarios:

  • Desktop notifications — A Notification hook fires a desktop alert when Claude needs your input, so you don't have to watch the terminal during long tasks.
  • Security auditing — A PreToolUse hook on the Bash tool logs every shell command Claude executes to an append-only audit file.
  • Blocking protected files — A PreToolUse hook on Edit, MultiEdit, and Write tools inspects the target file path and blocks writes to sensitive files like .env or anything inside .git/.
  • Test suite quality gates — A PostToolUse hook runs your test suite after Claude modifies source files, and if tests fail, pipes the error output back to Claude as context.
  • CI/CD automation — A PreToolUse hook evaluates whether a proposed tool invocation is safe to auto-approve in a headless pipeline, enabling autonomous operation without human approval at every step.

Hooks can also now be distributed as part of Claude Code Plugins — shareable bundles that install with a single command — making it easy to share formatting hook configurations across teams.

Is Setting Up Formatting Hooks Worth the Effort?

For any project where code style consistency matters, yes. The core value proposition is simple: once a formatting hook is in place, you never need to add "remember to run Prettier" to a prompt again, and you never get a PR where Claude's edits broke your formatting rules. The hook enforces the policy at the infrastructure level, not the prompt level.

The setup effort is low — for a basic Prettier hook on TypeScript files, you're editing a single JSON file and adding one hook definition. The payoff is permanent: every file Claude touches in that project will be formatted correctly, every time, without any ongoing maintenance.

For teams, storing the hook in the project-level .claude/settings.json means every developer who uses Claude Code on that project gets the same formatting behavior automatically — no individual setup required.

Frequently asked questions

What hook event should I use for automatic code formatting in Claude Code?

Use the PostToolUse hook event with a matcher targeting the Edit, MultiEdit, and Write tools. This fires after Claude completes a file write, letting you run your formatter on the newly written file before Claude moves on.

Will my formatting hook run even if I don't tell Claude to format the file?

Yes. That's the key advantage of hooks over prompt instructions. Hooks guarantee deterministic execution — they always run at the specified lifecycle point regardless of what Claude decides to do.

Can I use a formatting hook for multiple file types in the same project?

Yes. Your hook command can include conditional logic to check the file extension and run the appropriate formatter — for example, Prettier for TypeScript files and gofmt for Go files — all within a single hook definition.

Do I need to restart Claude Code after adding a formatting hook?

Only if you edited the settings JSON file directly. Changes made through the /hooks slash command inside Claude Code apply to new sessions automatically without a restart.

Can a PostToolUse formatting hook undo a file write if the formatter fails?

No. PostToolUse hooks run after the tool has already executed and cannot reverse file writes. If your formatter fails, the unformatted file remains on disk. Use exit codes and stderr output to signal the failure to Claude Code.

Which Claude Code plans support hooks?

Hooks are available on Pro, Max, Team, and Enterprise plans.

Go deeper

Hooks is one of 85 features in Claude Master — the independent, continuously updated manual with worked examples, the pitfalls, and the workflows that put Claude to work.

Get Claude Master — founding price →

Independent product. Not affiliated with or endorsed by Anthropic. "Claude" is a trademark of Anthropic, used here only to describe the subject of this guide.