Helm Hooks & Library Charts
Hooks run Kubernetes resources at specific lifecycle moments — migrations, smoke tests, cleanup. Library charts share helper templates across charts. Both are powerful but can surprise rollbacks and GitOps controllers if not designed carefully.
Hook Types
| Hook | When it runs | Common use |
|---|---|---|
pre-install | Before resources are installed | Prepare external dependency |
post-install | After install completes | One-time setup or notification |
pre-upgrade | Before upgrade applies | DB migration checks |
post-upgrade | After upgrade completes | Validation Job |
pre-delete | Before uninstall | Backup or graceful drain |
post-delete | After uninstall | External resource cleanup |
test | On helm test only | Smoke test Pod |
Hook Annotations
| Annotation | Purpose |
|---|---|
helm.sh/hook | Which lifecycle event(s) trigger this resource |
helm.sh/hook-weight | Execution order — lower numbers run first |
helm.sh/hook-delete-policy | When to delete the hook resource after it runs |
Migration Hook Job
This hook runs a Kubernetes Job before an upgrade, often for database migration checks or one-time setup. Use hooks sparingly, because failed hooks can block or wedge a release.
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ include "web-api.fullname" . }}-migrate"
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
backoffLimit: 1
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
command: ["./bin/migrate"]
envFrom:
- secretRef:
name: "{{ include "web-api.fullname" . }}-db"
Helm Test Hook
A test hook runs only when you execute helm test. Use it for lightweight smoke checks that verify the release works after install or upgrade without becoming part of the normal workload.
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "web-api.fullname" . }}-smoke"
annotations:
"helm.sh/hook": test
spec:
restartPolicy: Never
containers:
- name: curl
image: curlimages/curl:8.8.0
command:
- sh
- -c
- curl -fsS "http://{{ include "web-api.fullname" . }}:{{ .Values.service.port }}/health"
Library Charts
Library charts (type: library) provide shared templates but install no resources themselves. Parent charts import helpers via dependencies.
apiVersion: v2
name: common
type: library
version: 1.0.0
This helper template lives in the library chart and can be reused by parent charts. Use it to standardize labels, names, or common snippets across many internal app charts.
{{- define "common.labels" -}}
app.kubernetes.io/name: {{ .Chart.Name | quote }}
app.kubernetes.io/instance: {{ .Release.Name | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end -}}
In the parent chart's Chart.yaml, add common as a dependency, then call {{ include "common.labels" . }} in templates.
Commands
Use these commands to inspect hook output, run Helm tests, and see which hook resources Helm created. They are your first stop when a hook blocks an install or upgrade.
helm upgrade --install web-api ./charts/web-api -n app --wait --timeout 10m
helm test web-api -n app --logs
helm get hooks web-api -n app
# Debug a failed hook.
kubectl get jobs,pods -n app | grep -E 'migrate|hook'
kubectl logs job/web-api-migrate -n app
kubectl describe job/web-api-migrate -n app
Failed Hook Recovery
Use this during an incident where a hook Job failed or timed out. Inspect logs first, then delete only the failed hook resource if you are sure it is safe to retry or roll back.
# Release stuck in pending-upgrade because a hook Job failed.
helm status web-api -n app
kubectl logs job/web-api-migrate -n app
# Delete the failed hook Job so Helm can recreate it on retry.
kubectl delete job web-api-migrate -n app
# Retry the upgrade or rollback to last good revision.
helm rollback web-api -n app
helm upgrade web-api ./charts/web-api -n app -f values-prod.yaml --wait
helm upgrade. Confirm the client's GitOps tool supports hooks before relying on pre-upgrade migration Jobs in an Argo-managed release.Gotchas
- Hooks are not normal release resources — they may not appear in
helm get manifest. - Make migration hooks idempotent. Retried Jobs must not corrupt data.
- Use
hook-delete-policy: before-hook-creation,hook-succeededso old Jobs do not block future hook runs. - Library charts never install resources — only parent/application charts create Kubernetes objects.
- Hook failures leave the release in
pending-upgrade— check Job logs before retrying.