How do Helm hooks work and when do you use pre-install/post-install hooks?
Quick Answer
Helm hooks are specially annotated Kubernetes resources that execute at specific lifecycle points such as pre-install, post-install, pre-upgrade, and post-upgrade, allowing you to run database migrations, seed data, send notifications, or perform health checks outside the normal chart resource flow.
Detailed Answer
Think of Helm hooks like the opening act and encore at a concert. The main chart resources are the headline band, but sometimes you need a warm-up act to prepare the audience before the show starts and a cleanup crew after everyone leaves. Hooks give you precisely timed slots in the release lifecycle to run Jobs, Pods, or any Kubernetes resource that must execute before or after the main deployment, without being treated as a regular part of the release.
Helm supports several hook types that fire at different moments: pre-install and post-install run before and after all chart resources are created for a new release, pre-upgrade and post-upgrade bracket the upgrade of an existing release, pre-rollback and post-rollback surround rollback operations, pre-delete and post-delete fire during release uninstallation, and the test hook marks resources that only run during helm test. A resource becomes a hook by adding the helm.sh/hook annotation with one or more hook types as a comma-separated value. Hook resources are not managed as part of the regular release, meaning they do not appear in helm get manifest and are not upgraded or deleted with normal chart lifecycle operations unless you explicitly configure deletion policies.
Internally, when Helm reaches a hook point during a release operation, it sorts all hooks for that point by their weight annotation, with lower weights executing first. Hooks with the same weight execute in alphabetical order by resource name. Helm creates each hook resource and then waits for it to reach a completed state. For Jobs, this means the Job must succeed. For Pods, the container must exit with a zero exit code. If a hook fails, the entire release operation is aborted and marked as failed. The helm.sh/hook-weight annotation accepts string integer values, and the helm.sh/hook-delete-policy annotation controls when hook resources are cleaned up. The three deletion policies are hook-succeeded which deletes the resource after successful execution, hook-failed which deletes it after failure, and before-hook-creation which deletes any existing instance before creating a new one, preventing name collision errors on repeated installs.
In production, the most common hook pattern is a pre-upgrade Job that runs database migrations before new application pods roll out. This ensures the database schema is compatible with the new code version before any traffic hits it. Post-install hooks commonly seed initial data, register the service with a service mesh, or send deployment notifications to Slack or PagerDuty. Pre-delete hooks are valuable for draining connections, deregistering from load balancers, or creating final database backups before teardown. Teams running blue-green deployments often use post-upgrade hooks to run smoke tests against the new deployment before cutting traffic, giving an additional validation layer beyond Kubernetes readiness probes.
A critical gotcha with hooks is that they are not garbage-collected by default. If you omit the hook-delete-policy annotation, completed hook Jobs and their Pods persist in the namespace indefinitely, cluttering the cluster and potentially hitting resource quotas. Always set before-hook-creation as a minimum deletion policy so that subsequent installs or upgrades can recreate the hook resource without name conflicts. Another trap is setting hook weights incorrectly when you have dependent hooks, such as a migration hook that must finish before a seed-data hook. If both have the same weight, execution order falls to alphabetical naming, which is fragile. Assign explicit numeric weights to guarantee deterministic ordering across all environments.