Hooks
Hooks let you run commands before or after recipe execution — for setup, cleanup, notifications, and error recovery. There are three scopes: global (all recipes), targeted (one specific recipe), and recipe-internal (defined inside the recipe body).
Common Use Cases
Section titled “Common Use Cases”Service lifecycle — Spin up dependencies before a task and tear them down after, regardless of whether the task succeeds.
task test: @pre docker-compose up -d npm test @post docker-compose downDeployment notifications — Post to Slack, send a webhook, or update a status page after a deploy finishes or fails.
@after deploy curl -s -X POST $SLACK_WEBHOOK -d '{"text":"Deploy complete"}'@on_error deploy curl -s -X POST $SLACK_WEBHOOK -d '{"text":"Deploy FAILED"}'Automatic rollback — Trigger a rollback script if a deploy or migration fails.
@on_error deploy ./scripts/rollback.sh --env production@on_error migrate psql $DATABASE_URL -f migrations/rollback.sqlEnvironment validation — Check that required tools, credentials, or conditions exist before a recipe runs. Because pre-hook failures stop execution, this acts as a clean gate.
@before deploy ./scripts/check-env.sh@before release git diff --exit-code # fail if there are uncommitted changesTiming and audit logs — Record when tasks start and finish, useful in CI logs or for auditing long-running pipelines.
@pre echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] Starting {{JAKE_RECIPE}}"@post echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] Finished {{JAKE_RECIPE}}"Artifact cleanup — Remove temp files or caches after a build, whether it succeeded or not.
task build: npm run build @post rm -rf .tmp/ .cache/Cross-cutting CI concerns — Apply behaviors to multiple recipes without touching each one. Define them at the top of your Jakefile or in an imported module.
@before build ./scripts/ensure-node-version.sh@before test ./scripts/ensure-node-version.sh@before release ./scripts/ensure-node-version.shWhich Hook to Use
Section titled “Which Hook to Use”The choice between hook types is mostly about ownership: does the hook belong to the recipe, or is it an external concern?
Recipe-internal @pre / @post — Use inside a recipe body when the hook is tightly coupled to that task and should always run with it. The hook moves with the recipe, stays visible in the recipe definition, and is part of its contract.
task test: @pre docker-compose up -d # always runs before test npm test @post docker-compose down # always runs after testTargeted @before / @after — Use at the top level to attach behavior to a recipe you don’t want to modify. Useful for project-level conventions, CI-specific steps, or cross-cutting concerns defined in an imported file.
@before deploy echo "Checking deploy prerequisites..."@after deploy notify "Deployment complete"Global @pre / @post — Use when you want something to run regardless of which recipe is invoked.
@pre echo "=== Starting ==="@post echo "=== Done ==="Execution Order
Section titled “Execution Order”For any recipe that runs, hooks fire in this order:
- Global
@prehooks @beforehooks targeting this recipe- Recipe
@prehooks (inside recipe body) - Recipe commands
- Recipe
@posthooks (inside recipe body) @afterhooks targeting this recipe- Global
@posthooks @on_errorhooks (only if the recipe failed)
Error Hooks
Section titled “Error Hooks”@on_error runs when a recipe fails. Use it for notifications, cleanup that shouldn’t run on success, or logging:
@on_error echo "Build failed — check logs at ./build.log"@on_error notify "CI failure on {{BRANCH}}"@on_error hooks can also be targeted to a specific recipe:
@on_error deploy rollback --lastFailure Behavior
Section titled “Failure Behavior”Hook failures are handled differently depending on the hook type.
Pre-hooks — if a pre-hook fails, execution stops immediately. The recipe commands don’t run, and no post-hooks fire.
Post-hooks — all post-hooks always run, even if the recipe failed or an earlier post-hook failed. Errors are collected internally and the first one is returned after all post-hooks complete. This makes post-hooks reliable for cleanup — a failing notification hook won’t prevent a Docker container from being stopped.
@on_error hooks — failures are silently ignored. If your error hook itself errors, execution continues normally. Don’t rely on @on_error hooks for anything that must succeed.
Hooks in Parallel Execution
Section titled “Hooks in Parallel Execution”When running with -j (parallel execution), hooks fire per recipe, not globally for the parallel batch. Each recipe’s pre/post cycle runs in the thread executing that recipe. Global @pre and @post hooks still run for every recipe — they’re not deduplicated across parallel runs.
Variable Expansion in Hooks
Section titled “Variable Expansion in Hooks”Hook commands support the same {{variable}} expansion as recipe commands:
app = "myapp"
@before deploy echo "Deploying {{app}} to production..."@after deploy notify "{{app}} deployment complete"@on_error deploy notify "{{app}} deployment failed!"