skip to content

In a Helm umbrella chart with fourteen subcharts, when do you route a setting through global instead of repeating it per subchart?

level: principalimportance: should knowfreq 37%

answer

  1. Ask what the value is a property of
  2. Installation-wide fact versus component setting
  3. A flat namespace across independently versioned charts
  4. Duplication is verbose but blames one chart
  5. Diverging lifecycles mean separate releases

basics

~20 s

Use Helm's global block only for facts that belong to the installation itself — registry mirror, storage class, cluster domain — and that most subcharts genuinely read. Everything else is cheaper duplicated per subchart, where it diffs cleanly and its blast radius is one chart.

solid answer

~50 s

The test I apply is whether the value is a property of the **installation** or of a **component**. A registry mirror, a storage class, a cluster domain or an environment name is true of the whole install, is read by most of the tree, and belongs in `global`. A replica count, a resource request or a feature flag is true of one component and belongs in its own block, even when two subcharts happen to agree on it today. The cost of a global is that it is a flat namespace shared by charts versioned independently: it cannot be scoped, renaming it is a change to every chart at once, and editing it re-renders the whole tree — which for a fourteen-subchart umbrella means one seven-minute upgrade that can roll workloads nobody was thinking about. Duplication is verbose but honest, diffs cleanly and blames one chart. And when a subchart's lifecycle stops matching the rest, the right answer is usually not better plumbing but a separate release.

code

yaml · 15 lines
yaml
# transcode-platform/values.yaml — a small, deliberate global surface
global:
  storageClass: fast-nvme        # true of this cluster
  imageRegistry: mirror.example.internal

worker-gpu:
  replicaCount: 6                # true of this component only
  resources:
    limits:
      memory: 12Gi
ingest:
  replicaCount: 2
  resources:
    limits:
      memory: 3Gi

go deeper

for a junior

You will not be asked to make this call, but know the two options exist: a shared global block every chart can read, or the same key written into each subchart's own block, and that Helm offers nothing else.

for a middle

Be able to argue both sides concretely — what globals save in duplication and what they cost in scoping and reach — and recognise that a chart only honours a global its templates actually reference.

for a senior

Show that you reason about churn: a global feeds every render, so changing one can roll workloads well beyond the change you intended. Describe how you would preview and bound that before an upgrade.

for a principal

Own the release boundary, not just the values layout. Say when you would split an umbrella into separate releases with independent histories and blast radii, what that costs in ordering and visibility, and what you enforce in CI.

### The question underneath the question A fourteen-subchart umbrella with a values file no one can hold in their head is not usually suffering from bad key names. It is suffering from one release being asked to be the unit of change for fourteen things that change at different rates. Value plumbing is where that shows up first, so the plumbing decision is worth making explicitly rather than by accretion. ### The installation-versus-component test Helm gives you exactly two ways to say something to more than one chart: put it under `global`, where every chart in the tree can read it, or write it into each subchart's own block. Everything else is a variation on those. A value earns `global` when three things hold. First, it is a fact about *where this is installed*, not about what a component does — which registry mirror this cluster pulls from, which storage class exists here, what the cluster domain is, what to call this environment. Second, most of the tree genuinely reads it. Third, it is meaningfully the *same* value everywhere; if one subchart needs a different storage class, the global has already failed to express reality and half the tree is lying. A value belongs in a subchart's own block when it describes that component: replicas, resources, probes, feature toggles. Two subcharts having the same replica count this quarter is a coincidence, not a shared fact, and encoding a coincidence as a tree-wide contract is how a global namespace fills up with keys nobody can safely remove. ### What a global actually costs The cost is not YAML — it is the contract. Globals are one flat namespace with no scoping and no ownership, shared by charts that are versioned and released on their own schedules, including third-party ones you do not control. That produces three specific liabilities. **Nobody has to obey it.** Helm delivers a global into every chart's values, but a chart only acts on globals its own templates reference. Bundle a third-party subchart that ignores your registry global and you end up carrying the global *and* a per-chart override — the duplication you were avoiding, plus a tree-wide contract. **Removal is a fleet change.** Adding a global costs one line; renaming or deleting one is a coordinated change across every chart that reads it, and you cannot tell which those are from the values file alone. **Blast radius.** A global is an input to every render in the tree. Change it and all fourteen subcharts re-render inside one upgrade. If it feeds an image reference, or a chart that renders a Secret from a values key and annotates that Secret's checksum onto its pod template, the seven-minute upgrade you scheduled to change one thing rolls pods you did not intend to touch. For a transcoding pipeline where in-flight jobs die with their pods, that is an incident, not a formatting choice. Duplication has the opposite profile: verbose, but every occurrence is visible, greppable, diffable in review, and independently changeable. On a large umbrella I will take five duplicated storage-class lines over a global that six charts read and eight ignore. ### Where the real answer is release topology By the time the values file is the problem, the question has usually stopped being about values. Ask what a *change* costs. In one umbrella, every edit is one release revision covering fourteen components: a failed upgrade to any of them puts the whole release into a failed state, a rollback takes everything back, and the history for the media pipeline is interleaved with the history of the things around it. Split when lifecycles genuinely differ — when a subchart is upgraded on its own cadence, owned by another team, or carries a different risk profile. Separate releases get separate values files, separate revision histories and separate blast radii, and the coupling between them becomes an explicit input on each side rather than an implicit shared namespace. What you give up is single-command install ordering and one place to look, so the split earns its keep for a stable platform layer plus fast-moving apps, and does not for a genuinely atomic bundle. The middle position I most often land on: keep the umbrella for things installed and upgraded together, keep `global` small and deliberately documented in the parent's own `values.yaml` so it reads as an intentional surface, resist adding a global for anything under about half the tree, and pull out any subchart whose upgrade cadence has diverged. Then guard it in CI — render the umbrella and diff the manifest on every dependency bump and every values change, so a global edit that quietly restarts four unrelated workloads is visible in a pull request rather than at seven minutes into a production upgrade.

  • How would you make the blast radius of a global change visible before it ships?
    Render the umbrella before and after in CI and diff the manifest, not just the values. That surfaces every object the global touched, including pod templates whose annotations changed and will therefore roll. Attach the diff to the pull request so the reviewer sees that a one-line global edit restarts four workloads, rather than discovering it mid-upgrade.
  • A third-party subchart ignores your global. What do you do?
    Set its per-chart key explicitly and leave the global alone. Wrapping the chart to inject the value is possible but makes you the maintainer of someone else's chart, and post-render rewriting hides the change from the values file. The explicit override is visible, survives version bumps and costs one line; document beside it which charts do not honour the global.
  • What signals tell you an umbrella chart should become several releases?
    Subcharts upgraded on different cadences, owned by different teams, or with different risk appetites; a rollback that would drag unrelated components back; and a revision history where you cannot tell what changed. When one upgrade routinely restarts things nobody asked to touch, the release boundary is in the wrong place and no amount of values plumbing fixes it.
  • Is a values file that is thousands of lines long itself the problem?
    Not on its own — size mostly tracks how many components you install. The real signals are keys nobody can attribute to a chart, overrides duplicated because a global was not honoured, and edits whose effect cannot be predicted without rendering. Judge the file by whether a reviewer can tell what a change will do, not by its length.

saying these in an interview costs you the question

  • Moves every shared-looking value into global by default
  • Treats duplication as automatically worse than a global
  • Ignores that a global change re-renders every subchart
  • Assumes bundled third-party charts honour your globals
  • Never questions whether one release is the right boundary
  • Judges an umbrella purely by values-file line count

context