Lesson 4 · Helm fundamentals

Values & overrides

The precedence rules that make one chart serve every environment and every customer.

Your win: state the values precedence order (defaults → -f files → --set), explain global values, and read this repo's env×org layering — the mechanism behind Course 1's matrix.

Where values come from

A template reads .Values, but that object is merged from several sources. The precedence, lowest to highest:1

subchart values.yaml (lowest) ▼ overridden by the chart's own values.yaml ▼ overridden by -f file1.yaml -f file2.yaml (each -f wins over the last) ▼ overridden by --set key=value (highest — beats everything)

Two rules that trip people up: with multiple -f files, the last one wins; and merging is a deep merge for maps but lists are replaced wholesale, not concatenated.1

Global values — the one shared namespace

A subchart can't read its parent's values — except .Values.global, a reserved section readable by the parent and every subchart alike.2 It's how you set something once (an image tag, an environment name) and have it reach everywhere.

Anchor — the four-layer values stack Each service release layers four values files, in this precedence order (last wins), from skaffold.backend.yaml:22-25 / backend/bob/skaffold.yaml:11-15:
  1. gateway {env}-{org}-values.yaml
  2. backend/values.yaml — the shared global: block (image, VPA, Hasura defaults)
  3. backend/{env}-{org}-values.yaml — cross-service, per-cell
  4. backend/<svc>/{env}-{org}-values.yaml — the most specific, wins
So backend/bob/local-manabie-values.yaml (:42-45) only needs to hold the deltas for that cell — trimmed cpu/memory, a metrics toggle — because everything else comes from the layers below. Same chart, ~30 cells, tiny per-cell files. That's the env×org matrix from Course 1, in Helm.
Where env & org actually get set Skaffold also injects two values directly via setValueTemplates (skaffold.backend.yaml:27-31): global.environment: "{{.ENV}}" and global.vendor: "{{.ORG}}" (plus the image tag). Those are --set-style overrides — highest precedence — and the templates read them back through helpers util.environment / util.vendor (libs/util/templates/_env.tpl:6-16,37-47), which fall back from .Values.global.environment to .Values.environment. That's the exact wiring that turns "ENV=local ORG=manabie" into the right config everywhere.
values.yaml precedence, via Skaffold You rarely type helm -f … -f … here — Skaffold's valuesFiles: list is that ordered set of -f flags. Reordering the list changes who wins. Same Helm rule, expressed in the Skaffold release config.
Read this next

Helm docs — Values Files + Subcharts & Global Values

Where values come from, the precedence/merge rules, and how global works.

helm.sh — Values Files
helm.sh — Subcharts & Global Values

Check yourself (from memory)

Q1. Which wins when the same key is set several ways?

Lowest → highest: values.yaml → -f files (last wins) → --set. More specific overrides more general.

Q2. Which values can a subchart read from its parent?

global is the one shared section; otherwise a subchart can't see the parent's values.

Q3. This repo's per-cell {env}-{org}-values.yaml files are small because…

The shared global + defaults layers supply the rest; the per-cell file overrides just what differs (cpu, toggles).
Values precedence, global values, and this repo's env×org layering.
recall, then click to reveal
PRECEDENCE (low→high): subchart values.yaml → chart values.yaml → -f files (LAST wins) → --set (wins all). Maps DEEP-MERGE; lists are REPLACED wholesale. GLOBAL: .Values.global is the one section shared into subcharts (set once, read everywhere). REPO: four layered values files per release (Skaffold valuesFiles, last wins): gateway {env}-{org} → backend/values.yaml (shared global) → backend/{env}-{org}backend/<svc>/{env}-{org} (most specific). Per-cell files hold only DELTAS. env/org injected via setValueTemplates (global.environment/vendor), read via util.environment/util.vendor — Course 1's env×org matrix in Helm.
✅ Part 1 complete You have the fundamentals: what Helm is (L1), a chart's anatomy (L2), the template engine (L3), and how values layer (L4). Part 2 gets to the interesting part — this repo's library-chart architecture: named templates, the copied libs/util chart, hooks, and how Skaffold drives releases.
Ready for Part 2 (named templates & the library chart)? Or a mock interview on Part 1 — values precedence is a classic question. Ask me.

1. Helm — Values Files.

2. Helm — Subcharts and Global Values.