Lifecycle Hooks and Weights
Hooks let a chart run Jobs at defined points -- pre-install migrations, post-upgrade cache warms -- with weights to order them and delete policies to clean up.
Sometimes a resource must run around a release rather than as part of it — a database migration before the new Pods start, a smoke check after an upgrade, a cleanup job before uninstall. That is exactly what hooks are for.
The hook points you will actually use
pre-install/post-install— around the very first install.pre-upgrade/post-upgrade— around every upgrade. Schema migrations almost always belong inpre-upgrade.pre-delete/post-delete— around uninstall.test— the smoke tests from the previous lesson.
Ordering with weights
When several hooks share a phase, helm.sh/hook-weight orders them — lower runs first, and weights are strings that sort numerically. A negative weight is a common trick to force something to the very front.
Cleaning up with delete policies
Hook resources are not tracked as part of the release, so they linger unless you tell them not to. helm.sh/hook-delete-policy handles it: before-hook-creation (delete the previous run first — the sane default), hook-succeeded, and hook-failed.
Because hooks are outside normal release tracking, ahelm rollbackdoes not undo what a hook did. If apre-upgrademigration is destructive, your rollback plan needs a real down-migration, not a prayer.
Example
# templates/migrate-job.yaml -- run DB migrations before new Pods roll out
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ include "mychart.fullname" . }}-migrate"
annotations:
helm.sh/hook: pre-upgrade,pre-install
helm.sh/hook-weight: "-5" # runs before higher-weighted hooks
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
spec:
backoffLimit: 2
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
command: ["/app/manage", "migrate", "--no-input"]When to use it
- A chart author uses a pre-upgrade Job hook to run database migrations before new application Pods start, preventing the new code from running against an old schema.
- A developer assigns hook weights so a secret-rotation Job runs before a cache-warm Job within the same lifecycle phase, controlling the order of multi-step pre-upgrade tasks.
- A platform team adds a post-delete hook to archive the last release's configuration to S3 when a release is uninstalled, providing an audit trail without manual intervention.
More examples
Weighted pre-upgrade hooks
Shows two pre-upgrade hooks with different weights; lower weight runs first, giving fine-grained control over multi-step pre-upgrade sequences.
# Job 1 — runs first (weight -10)
metadata:
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-weight": "-10"
"helm.sh/hook-delete-policy": hook-succeeded
---
# Job 2 — runs second (weight 0)
metadata:
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": hook-succeededComplete migration job
A production-ready migration Job hook that runs before install and upgrade, cleans up on success, and is deleted before re-creation on the next run.
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-migrate
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"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: ["/app/migrate", "--db-url", "$(DB_URL)"]List active hooks
Displays all hook resources associated with the release, their hook annotations, and event phase so you can audit what runs at each lifecycle point.
helm get hooks my-release -n production
Discussion