skip to content

In a Helm chart, what does the helm.sh/hook-weight annotation control?

level: juniorimportance: should knowfreq 46%

answer

  1. A sequencing knob on hook manifests
  2. One event's hooks, sorted
  3. The value is a quoted string
  4. Lower numbers go first; zero is the default

basics

~20 s

helm.sh/hook-weight is a quoted integer that sorts the hooks firing on the same event, lowest first. Negatives are allowed and a missing annotation means 0. Helm runs each hook to completion before creating the next.

solid answer

~50 s

`helm.sh/hook-weight` is the sequencing knob for hooks. When a release reaches a hook event, Helm gathers every rendered manifest marked as a hook for that event, parses each one's `helm.sh/hook-weight` value as a signed integer, and sorts them ascending - so `"-5"` runs before `"0"`, which runs before `"10"`. The value must be a **quoted string**, because Kubernetes annotation values are strings; an unquoted `-5` is a YAML number and the manifest will not apply. A hook without the annotation is treated as weight 0. Helm then executes the sorted hooks one at a time: it creates a hook resource, waits for it to reach a finished state (a Job must complete, a Pod must succeed), and only then creates the next one - which is what makes the weight an actual execution order rather than just a creation order.

code

yaml · 25 lines
yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: fanout-shardmap
  annotations:
    "helm.sh/hook": pre-upgrade
    "helm.sh/hook-weight": "-10"
data:
  shards: "48"
---
apiVersion: batch/v1
kind: Job
metadata:
  name: fanout-reshard
  annotations:
    "helm.sh/hook": pre-upgrade
    "helm.sh/hook-weight": "0"
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: reshard
          image: registry.example.internal/fanout-tools:1.4.2
          args: ["reshard", "--from-configmap=fanout-shardmap"]

go deeper

for a junior

Recall three facts: the value is a quoted string, Helm sorts ascending so lower runs first, and a hook with no weight annotation is weight 0. Being able to write the annotation correctly in a Job manifest is the bar here.

for a middle

Explain the mechanics: which set of hooks the weight is compared against, that negatives are ordinary values, that Helm creates one hook and waits for it to finish before the next, and why the value must be quoted to survive apply.

for a senior

Show operational habits - leaving numeric gaps so hooks can be inserted later, checking rendered output for exact annotation values, and knowing that an unparsable weight silently becomes 0 rather than failing the release.

for a principal

Own the convention. Decide the weight bands a shared chart library uses, whether hook sequencing belongs in charts at all versus in the application's own startup logic, and how you keep subchart-contributed hooks from colliding with a platform team's numbering.

### What the annotation is `helm.sh/hook-weight` is an annotation Helm reads off a rendered manifest that has already been marked as a hook. It does one job and only one: it decides the relative order of the hooks that fire on the *same* hook event of the *same* release operation. It has no effect on a manifest that is not a hook, and it never orders a hook against the chart's ordinary resources. ### The value is a string that Helm parses as an integer Kubernetes annotation values are strings, always. So the weight must be written quoted: ```yaml annotations: "helm.sh/hook-weight": "-5" ``` Writing `helm.sh/hook-weight: -5` produces a YAML integer, and the API server rejects the object because the annotations map cannot hold a number. This is the single most common first mistake with the annotation, and it fails at apply time rather than at render time, so `helm template` will happily print it. Helm parses the string as a signed integer. The full integer range is available and negatives are ordinary values, not a special case. A hook manifest that carries no `helm.sh/hook-weight` at all is treated as weight 0, which means an unannotated hook is not "first" or "last" - it sits in the middle of the scale, alongside every other unannotated hook. A value Helm cannot parse as an integer is also treated as 0 rather than failing the operation, so a typo such as `"1O"` (letter O) silently sinks the hook into the default group instead of raising an error. ### Ascending, within one event Helm sorts ascending: lower weights run earlier. The comparison pool is the set of hooks selected for the event that is currently executing - and that pool includes hooks contributed by enabled subcharts, which are flattened into the same release and sorted alongside the parent's. It does **not** include hooks for other events. If the same manifest is annotated to fire on more than one event, the same weight is used each time it fires, compared only against the other hooks running in that particular cycle. The scale is relative, not absolute. `"-1000"` and `"-5"` behave identically if nothing else sits between them. Because of that, authors usually leave gaps - `-10`, `0`, `10`, `20` - so a later hook can be inserted between two existing ones without renumbering the chart. ### Weight is an execution order, not just a creation order The reason weights are useful at all is that Helm does not fire the sorted hooks and walk away. It processes them one at a time: create the resource, wait for it to reach a finished state, then move to the next. For a Job that means the Job must reach completion; for a bare Pod, the Pod must reach `Succeeded`; for a resource with nothing to finish, such as a ConfigMap or a Secret, the wait resolves immediately. If a hook fails, the operation stops there and the remaining, higher-weighted hooks are never created. This per-hook wait is unconditional - it is not the same thing as waiting for the chart's own workloads to become ready, which is a separate decision controlled by the wait strategy of the `install`/`upgrade` command. Helm waits for hooks either way. ```yaml apiVersion: batch/v1 kind: Job metadata: name: fanout-preflight annotations: "helm.sh/hook": pre-upgrade "helm.sh/hook-weight": "-5" spec: template: spec: restartPolicy: Never containers: - name: preflight image: registry.example.internal/fanout-tools:1.4.2 args: ["preflight"] ``` ### What it does not do Two limits are worth holding on to. First, a weight is not a dependency declaration: it expresses "before" and "after", not "only if". Helm has no notion of a hook that depends on another hook succeeding beyond the fact that a failure aborts the rest of the phase. Second, the weight cannot position a hook among the chart's normal resources - those are applied as their own phase, and no integer will interleave a hook into it. If the ordering you need crosses that boundary, the weight is the wrong tool and the manifest usually has to move into the hook phase or the work has to move to a later event.

  • What happens if you write the weight unquoted, as helm.sh/hook-weight: 5?
    The rendered YAML then holds an integer where an annotation value must be a string, so the API server refuses the object when Helm applies it. The render itself succeeds, which is why the mistake often survives review and only shows up as an apply-time type error on the annotations map. Always quote the value.
  • Does a weight of -100 guarantee a hook runs before everything else in the release?
    Before every other hook in that event, yes, as long as nothing else uses a lower number. Not before the release as a whole: hooks for other events still run in their own phases, and the chart's ordinary manifests are applied in a separate phase that no weight can reach into.
  • How does Helm treat a weight it cannot parse, such as "first"?
    It falls back to 0 rather than failing the operation, so the hook quietly joins the default group instead of erroring. That makes a typo hard to spot: the release succeeds and the hook simply runs at the wrong point. Reviewing rendered output for the exact annotation values is the practical defence.

Think of boarding groups on a flight: the number tells you when you get on relative to the other passengers, everyone without a printed number lands in the same middle group, and nobody's number lets them board before the crew.

saying these in an interview costs you the question

  • Says higher weights run first
  • Writes the weight unquoted as a YAML number
  • Thinks an unannotated hook runs last
  • Claims the weight orders hooks against the chart's Deployments
  • Believes Helm creates all hooks at once and lets them race
  • Treats the weight as a dependency or conditional declaration

context