In Helm, how does a parent chart's values.yaml pass values down to a subchart?
answer
- Parent and children become one values tree
- The key is named for the dependency
- An alias renames that key
- Parent values beat the subchart's defaults
- null deletes; lists replace
basics
~10 sThe parent sets a subchart's values under a top-level key named for that dependency, or for its alias when the dependency declares one. Those parent values override the subchart's own values.yaml defaults.
solid answer
~50 sHelm coalesces the whole chart tree into one values object before rendering anything. Whatever the parent puts under a top-level key matching the dependency's `name` — or its `alias`, when the dependency declares one — becomes that subchart's `.Values` root, and it beats the subchart's own `values.yaml` defaults key by key. Nesting mirrors the dependency graph, so a grandchild is reached as `child.grandchild.key`. The flow is one-way: a subchart's templates see only their own block plus `.Values.global`, never the parent's other keys, while the parent can read a child's resolved values through `.Subcharts.<name>.Values`. Setting a key to `null` in the parent deletes the child's default instead of blanking it, and a list in the parent replaces the child's list rather than merging with it. `helm install --dry-run=client --debug` prints the computed values Helm hands the templates.
code
yaml · 9 lines# transcode-platform/Chart.yaml
apiVersion: v2
name: transcode-platform
version: 1.9.3
dependencies:
- name: worker
version: 2.4.1
repository: oci://registry.example.internal/charts
alias: worker-gpugo deeper
Be ready to point at the exact key: a subchart's values live under a top-level key named for the dependency, or its alias. Know that the parent's setting wins over the subchart's own default.
Explain the coalescing step — one merged values tree built before rendering, maps merged key by key, lists replaced, null deleting a key — and that a subchart sees only its own block plus global.
Show how you debug a silently-ignored override: compare the subchart's published defaults with the computed values tree from a client-side dry run, and check for an alias or a missing level of nesting.
Own the consequence: one release means one values surface for the whole tree, so every override path is a coupling to a subchart's internal key layout that upgrading that subchart can break.
### One tree of values, assembled before anything renders A chart that lists `dependencies` in `Chart.yaml` is an umbrella chart: the parent plus every subchart it pulls under `charts/` are loaded together, rendered together, and installed as **one** release. That last point matters for values, because there is no separate "subchart install" with its own inputs. Helm builds a single merged values object for the whole tree first, then renders every template against a view of it. The merge rule is simple and mechanical. Helm walks the parent's values (its `values.yaml` defaults, plus whatever the caller supplied) and, for each declared dependency, looks for a top-level key whose name equals the dependency's `name`. If the dependency declares an `alias`, the alias is the key instead — the chart's own name no longer appears. Everything under that key becomes the subchart's `.Values` root. So the subchart's template writing `.Values.replicaCount` is reading the parent's `worker.replicaCount`. ```yaml # transcode-platform/Chart.yaml apiVersion: v2 name: transcode-platform version: 1.9.3 dependencies: - name: worker version: 2.4.1 repository: oci://registry.example.internal/charts alias: worker-gpu ``` ```yaml # transcode-platform/values.yaml worker-gpu: # the alias, not "worker" replicaCount: 6 encoder: threads: 12 ``` ### Which side wins The parent wins. Helm coalesces per key: a key the parent sets overrides the subchart's default for that key; a key the parent never mentions keeps the subchart's default. Maps are merged key by key, so setting `worker-gpu.encoder.threads` leaves the rest of the subchart's `encoder` block intact. **Lists are not merged** — supplying a list from the parent replaces the child's list wholesale, which is the usual surprise when overriding a chart's `env`, `tolerations` or `extraArgs`. Setting a key to `null` is a delete: it removes the child's default from the merged tree rather than setting it to an empty string, which is how you get rid of an unwanted default a subchart ships. ### The nesting follows the dependency graph A subchart may have dependencies of its own. From the top-level chart you reach them by chaining the keys: `worker-gpu.encoder.audio.bitrateKbps`. There is no shortcut and no search — the path is exactly the shape of the tree. This is where umbrella values files get deep, and it is why a nested override that looks right can silently land nowhere: a typo in a middle segment just creates a new, unused key, because Helm does not reject unknown values unless the chart ships a `values.schema.json` that forbids them. ### Visibility is one-way A subchart's templates can read two things: their own block, and `.Values.global`. They cannot see the parent's other top-level keys and they cannot see a sibling's block. That is deliberate — a subchart is meant to be installable on its own, so it must not depend on who wrapped it. The parent, by contrast, can look down. Inside a parent template, `.Subcharts.<name>.Values` exposes a child's resolved values, which is occasionally useful when the parent renders a resource that must agree with a child's rendered name or port. It is read-only and render-time only; you cannot write into a child that way. One thing that is *not* scoped per chart: the release. `.Release.Name`, `.Release.Namespace` and `.Release.Revision` are identical in the parent and in every subchart, because there is only one release record. ### Seeing what actually happened Three commands answer most "why did my override do nothing" questions: ```bash helm show values oci://registry.example.internal/charts/worker --version 2.4.1 helm install transcode transcode-platform/ --dry-run=client --debug helm get values transcode ``` The first prints the subchart's own defaults, so you can see the exact key names it expects. The second renders locally and prints the computed values tree Helm hands the templates — if your override is not in that tree under the key you expected, the path is wrong. The third shows what a live release was actually given, which is the fastest way to settle an argument about a running install. ### The everyday failure modes Almost every subchart-values bug is one of four things: the dependency was aliased and the values file still uses the chart's real name; the path is missing a level of nesting; a list override replaced more than intended; or the subchart never reads the key you set, because you invented a key name it does not implement. The last one is worth internalising — Helm passes values down, it does not make a chart honour them.
- The dependency declares `alias: worker-gpu`. Which key does the parent use, and what happens to the old one?The alias replaces the chart name entirely: values go under `worker-gpu`, and a block still named `worker` is inert — Helm carries it in the values tree but no chart reads it. Aliasing is what lets the same chart appear twice in one umbrella, each copy with its own values block and its own rendered resource names.
- Can a subchart read a value the parent set for a sibling subchart?No. A subchart's templates see only their own block plus `.Values.global`. That isolation is what keeps a subchart independently installable. If two subcharts genuinely need the same fact, either set it twice or put it under `global`. The parent can read downward with `.Subcharts.<name>.Values`, but that is parent-to-child only.
- You set `worker-gpu.tolerations` in the parent and the subchart's own tolerations disappeared. Why?Helm merges maps key by key but replaces lists outright. Supplying `tolerations` from the parent substitutes your list for the subchart's default list rather than appending to it. If you want both, restate the entries you still need. The same rule bites with `env`, `extraArgs` and `volumeMounts`.
The parent's values file is a set of addressed pigeonholes: each subchart only ever opens the one with its own name on it, plus the shared noticeboard marked global.
saying these in an interview costs you the question
- Thinks a subchart can read the parent's other top-level values
- Keeps using the chart's real name after declaring an alias
- Believes the subchart's values.yaml overrides the parent's
- Expects a list override to merge with the subchart's list
- Thinks each subchart becomes its own Helm release
- Assumes setting null blanks a key rather than deleting it