Mastering Claude Code Hooks: Auto-Format, Auto-Test, and More
Learn how to set up auto-formatting and auto-testing with Claude Code hooks. Includes practical configuration examples and real-world use cases.
What Are Hooks?
Claude Code hooks let you automatically run custom commands before or after specific actions. You can set up auto-formatting after file saves, auto-run tests after code changes, and much more.
Hooks are defined in .claude/settings.json and execute shell commands when Claude Code performs certain operations.
Hook Types
Claude Code supports hooks at the following event points:
| Hook Event | When It Fires |
|---|---|
PreToolUse | Before a tool is executed |
PostToolUse | After a tool is executed |
Notification | When a notification is sent |
Stop | When Claude Code finishes responding |
Basic Configuration
Hooks are defined in the hooks field of .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\""
}
]
}
}
Configuration Structure
- matcher: A regex pattern that matches the tool name triggering the hook
- command: The shell command to execute
Use Case 1: Auto-Formatting
Automatically run Prettier after any file edit:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\""
}
]
}
}
With this setup, every time Claude Code creates or edits a file, Prettier formats it automatically. Your team’s coding style stays consistent without any manual effort.
Use Case 2: Auto-Linting
Here’s how to integrate ESLint auto-fix:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
}
]
}
}
The || true suffix prevents lint errors from causing the hook to fail, allowing Claude Code to continue processing.
Use Case 3: Auto-Testing on Change
Automatically run related tests after file edits and feed back the results:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "npx vitest related \"$CLAUDE_FILE_PATH\" --run 2>&1 | tail -20"
}
]
}
}
Vitest’s related option runs only the tests relevant to the changed file, giving you much faster feedback than a full test suite.
Use Case 4: Auto Type-Checking
Run TypeScript type checking after file changes:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "npx tsc --noEmit 2>&1 | head -30"
}
]
}
}
Use Case 5: Blocking Dangerous Commands
A PreToolUse hook that prevents execution of risky commands:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "if echo \"$CLAUDE_TOOL_INPUT\" | grep -qE 'rm -rf|drop table|git push.*force'; then echo 'BLOCKED: Dangerous command detected' >&2; exit 1; fi"
}
]
}
}
When the hook exits with code 1, Claude Code skips the tool execution entirely.
Use Case 6: Completion Notifications
Send a notification when Claude Code finishes a task:
{
"hooks": {
"Stop": [
{
"matcher": "",
"command": "notify-send 'Claude Code' 'Task completed' 2>/dev/null; echo 'Done'"
}
]
}
}
On macOS, you can use:
{
"hooks": {
"Stop": [
{
"matcher": "",
"command": "osascript -e 'display notification \"Task completed\" with title \"Claude Code\"'"
}
]
}
}
Combining Multiple Hooks
In real projects, combining several hooks is the most effective approach:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "if echo \"$CLAUDE_TOOL_INPUT\" | grep -qE 'rm -rf /'; then exit 1; fi"
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
},
{
"matcher": "Write|Edit",
"command": "npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
}
],
"Stop": [
{
"matcher": "",
"command": "echo '✓ Task completed'"
}
]
}
}
Tips for Writing Hooks
1. Keep Execution Time Short
Hooks run synchronously, so heavy operations will slow down Claude Code’s responses. Use options like related to narrow test scope, and head or tail to trim output.
2. Handle Errors Gracefully
A hook that exits with an error can disrupt Claude Code’s workflow. Use || true and 2>/dev/null to keep things safe.
3. Use Environment Variables
Take advantage of the environment variables available in hooks. $CLAUDE_FILE_PATH gives you the path of the file being operated on.
Conclusion
Hooks let you heavily customize Claude Code’s workflow. The combination of auto-formatting and auto-testing is especially powerful for maintaining code quality. Start with Prettier auto-formatting and build from there.