How to Use Helm Hooks for Lifecycle Management
Master Helm hooks for pre-install, post-install, pre-upgrade, and post-delete operations. Learn to run database migrations, backups, and cleanup tasks.
π‘ Quick Answer: Add
helm.sh/hookannotation to Jobs or Pods to run at lifecycle points:pre-install,post-install,pre-upgrade,post-upgrade,pre-delete,post-delete. Usehelm.sh/hook-weightfor ordering andhelm.sh/hook-delete-policyto clean up hook resources.Key pattern: Database migrations use
pre-upgradehooks; backups usepre-deletehooks.Gotcha: Hooks run to completion before Helm continuesβset
activeDeadlineSecondsand usehook-faileddelete policy to prevent stuck releases.
Helm hooks allow you to execute operations at specific points during a release lifecycle. Use them for database migrations, backups, notifications, and cleanup tasks.
Understanding Hook Types
# Hook annotations for different lifecycle events
annotations:
"helm.sh/hook": pre-install # Before resources installed
"helm.sh/hook": post-install # After resources installed
"helm.sh/hook": pre-upgrade # Before upgrade
"helm.sh/hook": post-upgrade # After upgrade
"helm.sh/hook": pre-delete # Before deletion
"helm.sh/hook": post-delete # After deletion
"helm.sh/hook": pre-rollback # Before rollback
"helm.sh/hook": post-rollback # After rollbackDatabase Migration Hook
# templates/migration-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-db-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:
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
command: ["./migrate.sh"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-db-secret
key: url
backoffLimit: 3Pre-Install Validation Hook
# templates/pre-install-check.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-pre-check
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-10"
"helm.sh/hook-delete-policy": hook-succeeded,hook-failed
spec:
template:
spec:
restartPolicy: Never
containers:
- name: check
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
echo "Checking prerequisites..."
# Verify namespace exists
kubectl get namespace {{ .Values.targetNamespace }} || exit 1
# Check for required secrets
kubectl get secret required-secret -n {{ .Values.targetNamespace }} || exit 1
echo "All checks passed!"
backoffLimit: 1Post-Install Notification Hook
# templates/post-install-notify.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-notify
annotations:
"helm.sh/hook": post-install,post-upgrade
"helm.sh/hook-weight": "5"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: notify
image: curlimages/curl:latest
command:
- /bin/sh
- -c
- |
curl -X POST {{ .Values.slack.webhookUrl }} \
-H 'Content-Type: application/json' \
-d '{
"text": "β
{{ .Release.Name }} deployed successfully to {{ .Release.Namespace }}",
"attachments": [{
"color": "good",
"fields": [
{"title": "Version", "value": "{{ .Chart.Version }}", "short": true},
{"title": "App Version", "value": "{{ .Chart.AppVersion }}", "short": true}
]
}]
}'
backoffLimit: 1Pre-Delete Backup Hook
# templates/pre-delete-backup.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-backup
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation
spec:
template:
spec:
restartPolicy: Never
containers:
- name: backup
image: postgres:15
command:
- /bin/sh
- -c
- |
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
pg_dump $DATABASE_URL > /backup/{{ .Release.Name }}-$TIMESTAMP.sql
echo "Backup completed: {{ .Release.Name }}-$TIMESTAMP.sql"
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-db-secret
key: url
volumeMounts:
- name: backup-storage
mountPath: /backup
volumes:
- name: backup-storage
persistentVolumeClaim:
claimName: backup-pvc
backoffLimit: 1Hook Weight for Ordering
# Run in order: -10 β -5 β 0 β 5 β 10
# templates/hook-order-example.yaml
# First: Create config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-init-config
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-10"
data:
init.sql: |
CREATE DATABASE IF NOT EXISTS myapp;
# Second: Run migrations
---
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-schema
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-5"
spec:
template:
spec:
restartPolicy: Never
containers:
- name: schema
image: myapp:migrate
command: ["./schema.sh"]
# Third: Seed data
---
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-seed
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "0"
spec:
template:
spec:
restartPolicy: Never
containers:
- name: seed
image: myapp:seed
command: ["./seed.sh"]Hook Delete Policies
# Delete policy options
annotations:
# Delete hook resource before new hook is launched
"helm.sh/hook-delete-policy": before-hook-creation
# Delete when hook succeeds
"helm.sh/hook-delete-policy": hook-succeeded
# Delete when hook fails
"helm.sh/hook-delete-policy": hook-failed
# Combine multiple policies
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeededTest Hook for Validation
# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: {{ .Release.Name }}-test
annotations:
"helm.sh/hook": test
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
restartPolicy: Never
containers:
- name: test
image: busybox:latest
command:
- /bin/sh
- -c
- |
echo "Testing {{ .Release.Name }} connectivity..."
wget -qO- http://{{ .Release.Name }}-service:{{ .Values.service.port }}/health
echo "Test passed!"Run tests with:
helm test my-releaseCommon Pitfalls
- Hook resources are not managed - Theyβre not part of the release
- Failed hooks block installation - Use appropriate delete policies
- Hook weight is string - Must be quoted in YAML
- Hooks run every upgrade - Design for idempotency
Summary
Helm hooks enable powerful lifecycle automation for your releases. Use pre-install hooks for setup and validation, post-install for notifications, and pre-delete for backups and cleanup.
π Go Further with Kubernetes Recipes
Love this recipe? Thereβs so much more! This is just one of 100+ hands-on recipes in our comprehensive Kubernetes Recipes book.
Inside the book, youβll master:
- β Production-ready deployment strategies
- β Advanced networking and security patterns
- β Observability, monitoring, and troubleshooting
- β Real-world best practices from industry experts
βThe practical, recipe-based approach made complex Kubernetes concepts finally click for me.β
π Get Your Copy Now β Start building production-grade Kubernetes skills today!

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
