What does the helm.sh/hook annotation do to a manifest in a Helm chart's templates/ directory?
answer
- One extra line on an ordinary manifest
- Runs at a named point in the lifecycle
- Helm blocks until it reports ready
- Kept out of the release manifest
- helm.sh/hook: pre-install, comma-separated events
basics
~20 sIt turns that manifest into a lifecycle hook. Helm keeps it out of the release manifest and applies it on its own at the named point, such as pre-install or post-upgrade, waiting for it to succeed before the operation continues.
solid answer
~40 s`helm.sh/hook: pre-install` (or any of Helm's nine event names) marks an otherwise ordinary manifest under `templates/` as a hook. Helm renders it with everything else, then lifts it out of the release manifest and stores it in a separate hook list on the release, so it is applied only when its event fires. At that moment Helm creates the resource and blocks until it is ready — for a Job, successful completion — before the operation moves on; a hook that never succeeds fails the operation. One annotation may list several events comma-separated, so a single Job can serve `post-install,post-upgrade`. Because hooks sit outside the release manifest, `helm get manifest` never shows them (`helm get hooks` does), and Helm does not patch, prune or roll back whatever they create.
code
yaml · 9 linesapiVersion: v1
kind: Secret
metadata:
name: gateway-bootstrap-token
annotations:
"helm.sh/hook": pre-install,pre-upgrade
type: Opaque
stringData:
token: "{{ .Values.bootstrap.token }}"go deeper
Be ready to say what the annotation is for in one sentence: it makes a manifest run at a named lifecycle point instead of being applied with the rest of the chart. Knowing pre-install and post-upgrade by name is enough at this level.
Explain the mechanics: Helm renders the hook, removes it from the release manifest, applies it when the event fires, and blocks until it is ready before continuing. Mention that any kind can be a hook and that one annotation can list several events.
Show that you know the cost of the exclusion — hook resources are not diffed, pruned or rolled back — and that you would reject a chart that uses a hook to manage long-lived state. Knowing helm get hooks as a diagnostic separates you here.
Own the guidance your charts are written against: hooks are for one-shot side effects with a clear success signal, everything convergent belongs in the release manifest. Be able to say what that rule buys a fleet whose releases must be rollback-safe.
### What a hook actually is Everything under a chart's `templates/` directory renders to Kubernetes manifests. Helm normally gathers all of them into one document — the **release manifest** — and applies that document as a unit, storing it in the release record. A hook is the exception to that flow. Any rendered manifest carrying the annotation `helm.sh/hook` is lifted out of the release manifest before anything is applied and held in a separate hook list attached to the release, to be applied on its own at the lifecycle point the annotation names. ```yaml apiVersion: batch/v1 kind: Job metadata: name: {{ include "gateway.fullname" . }}-schema annotations: "helm.sh/hook": pre-upgrade spec: backoffLimit: 0 template: spec: restartPolicy: Never containers: - name: migrate image: registry.example.com/gateway-migrator:4.11.2 ``` Nothing else about the manifest is special. It is a normal Job that a normal cluster would accept; the annotation is the whole difference. ### The nine events The annotation's value is one of nine event names: `pre-install`, `post-install`, `pre-upgrade`, `post-upgrade`, `pre-rollback`, `post-rollback`, `pre-delete`, `post-delete` and `test`. The `pre-` events run after templates have been rendered but before Helm touches the cluster for that operation; the `post-` events run after all of the operation's resources have been applied. `test` is inert during install and upgrade and is applied only when someone runs `helm test` against the installed release. A value may list more than one event, comma-separated — `helm.sh/hook: post-install,post-upgrade` is the idiom for "run this every time the chart is deployed, first time or not". ### What Helm does when the event fires Helm applies the hook resource and then **blocks on it**. It waits until the resource reports ready — for a Job that means it completed successfully — before continuing to the rest of the operation. If the hook never gets there, the operation fails when the timeout expires. That wait is unconditional and is not the same knob as waiting for the chart's own workloads: in Helm 4 the `--wait` flag is strategy-valued and defaults to `hookOnly`, which is exactly this — Helm waits for hooks but not for your Deployments unless you ask for `watcher` or `legacy`. Helm 3's boolean `--wait` was off by default and also always waited on hooks. ### Hooks live outside the release manifest This is the part candidates miss, and it has consequences well beyond a CLI quirk. `helm get manifest <release>` prints the release manifest and will not show your hook; `helm get hooks <release>` prints the hooks that Helm stored for the current revision. Because an upgrade is computed by comparing release manifests, an object a hook created is never diffed, never patched, never pruned when it disappears from the chart, and never restored by `helm rollback`. Helm treats hooks as **one-shot actions**, not as managed state. A hook that creates a long-lived object is therefore creating an orphan the release does not own. ### Any kind can be a hook Job and Pod dominate because they run to completion and completion is a meaningful success signal. But the annotation is not restricted to them. A ConfigMap or Secret annotated `pre-install` is applied and considered ready immediately, which is how a chart seeds a credential a workload will mount moments later; a ServiceAccount, Role and RoleBinding a migration Job needs are commonly annotated with the same event so they exist before the Job that uses them. ### Reading a hook's output Because a hook runs inside the cluster, its output does not naturally reach the terminal you typed `helm upgrade` into. The annotation `helm.sh/hook-output-log-policy` fixes that: give it `hook-succeeded`, `hook-failed`, or both comma-separated, and Helm prints that hook Pod's logs to its own output on the matching condition, so you do not have to race to `kubectl logs`. ### Where people go wrong The two classic errors are assuming a hook is just "a Job Helm runs" — it is a phase, and Helm stops the world for it — and assuming a hook's resources are part of the release. Anything that must converge with the chart, be pruned when removed and be restored on rollback belongs in the release manifest as an ordinary template, not behind a hook annotation.
- Does a hook have to be a Job?No. Any kind the chart renders can carry `helm.sh/hook`. Job and Pod are the usual choices because running to completion is a clear success signal, but a ConfigMap, Secret, ServiceAccount or RBAC object annotated with the same event is applied at that point and treated as ready immediately — which is how charts create the permissions or credentials a hook Job or the workload itself needs a moment later.
- How do you see what a hook Job printed without reaching for kubectl?Annotate the hook with `helm.sh/hook-output-log-policy`. Its value is `hook-succeeded`, `hook-failed`, or both comma-separated, and Helm prints that hook Pod's logs into its own output when the matching condition occurs. It is the difference between an operator seeing the migration's error in the CI job log and having to go find a Pod in the cluster afterwards.
- For an installed release, how do you confirm which manifests Helm treated as hooks?`helm get hooks <release>` prints the hook manifests stored with the current revision; `helm get manifest <release>` prints everything else. If a resource you expected to see is missing from the second and present in the first, it is a hook — which also tells you Helm will not reconcile or prune it on later upgrades.
A hook is the stagehand, not the scenery: it runs on before the curtain goes up, does one job, and is never part of the set the audience sees listed in the programme.
saying these in an interview costs you the question
- Thinks only Jobs and Pods can carry the annotation
- Expects hook resources to appear in helm get manifest
- Assumes Helm deletes a hook's resources when the chart drops them
- Puts the hook annotation in values.yaml instead of on the manifest
- Believes hooks are applied alongside the chart's own resources
- Says a pre-install hook also runs on every upgrade