How does a chart's values.schema.json keep three per-environment values files to one shape?
answer
- A contract in the chart root
- Checked at install, upgrade, template and lint
- Applied after everything is merged
- Typos only fail when extras are forbidden
- Shape, never meaning
basics
~20 svalues.schema.json sits in the chart root, and Helm validates the merged values against it on install, upgrade, template and lint. An environment file that misspells a key or supplies the wrong type fails there, before anything renders.
solid answer
~40 sThe schema is JSON Schema and it is applied to the **final coalesced values** — chart defaults plus every `-f` file and `--set` — not to each file separately. So `required` means present after merging, a key the chart defaults always supply will always pass, and the interesting constraints are the ones that catch a per-environment file going wrong: a type mismatch such as `replicaCount: "11"` as a string, an `enum` rejecting `logLevel: verbose`, or `additionalProperties: false` catching `replicacount` misspelled — which Helm would otherwise accept and ignore. To hold *all three* environments to one shape you have to run the validation against all three: `helm lint charts/fraud-platform -f values/<env>.yaml` for each environment in CI, not just the one being deployed. Each subchart's own schema validates its own section of the values.
code
json · 23 lines{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": false,
"required": ["api", "worker"],
"properties": {
"api": {
"type": "object",
"additionalProperties": false,
"required": ["ingress"],
"properties": {
"replicaCount": { "type": "integer", "minimum": 2 },
"logLevel": { "type": "string", "enum": ["debug", "info", "warn", "error"] },
"ingress": {
"type": "object",
"required": ["host"],
"properties": { "host": { "type": "string" } }
}
}
},
"worker": { "type": "object" }
}
}go deeper
Know that a chart may carry a values.schema.json next to values.yaml, that Helm checks values against it, and that a failure means your values file, not the cluster, is wrong.
Explain that validation runs against the merged values on install, upgrade, template and lint, and which constraints matter in practice — types, enums, bounds and additionalProperties for catching misspelled keys.
Show how you make it a promotion guard: validate every environment's file on every change rather than the one being deployed, and be clear about the drift a schema cannot see, such as a correct shape pointing at the wrong environment.
Decide how strict the contract should be. A tight schema catches typos and blocks experimentation; argue where that line sits, who owns the schema when platform and application teams share the chart, and what the schema does not excuse you from testing.
## What the file is `values.schema.json` is an optional JSON Schema document in the chart's root directory, beside `Chart.yaml` and `values.yaml`. When it is present, Helm validates the values against it and refuses to proceed if they do not conform, naming the chart and the offending path. Validation runs on `helm install`, `helm upgrade`, `helm template` and `helm lint`, which is what makes it useful as a promotion guard: the same check that would stop a bad production deploy can be run in a pull request with no cluster in sight. ## The one fact people get wrong The schema is applied to the **merged** values, after chart defaults, every `-f` file and every `--set` have been combined — not to each file in isolation. Two consequences follow. First, `required` does not mean 'the environment file must set this'. If `values.yaml` supplies a default for the key, the merged document always has it and the requirement is always satisfied. `required` only bites for keys the chart deliberately leaves unset, which is exactly how you force every environment to declare, say, its ingress hostname rather than silently inheriting someone else's. Second, validating the environment you happen to be deploying tells you nothing about the other two. Holding three files to one shape is a CI job, not a property of the file: ```bash for env in dev staging prod; do helm lint charts/fraud-platform -f "values/${env}.yaml" done ``` ## The constraints that actually catch drift **Types.** YAML makes `replicaCount: "11"` a string, and a template that does arithmetic on it fails in a way whose error points at the template, not at the file. `"type": "integer"` fails at the front door instead. **Enums and patterns.** `logLevel` constrained to `debug|info|warn|error` stops a production file acquiring `verbose` because the application once accepted it. A `pattern` on an image tag can stop `latest` reaching production. **Bounds.** `"minimum": 2` on a production replica count encodes an operational rule in a place the deploy cannot bypass. **`additionalProperties: false`.** This is the strongest anti-drift constraint and the least used. Without it, a misspelled key in an environment file is not an error at all — Helm merges `replicacount: 11` into the values, no template reads it, and the environment quietly runs the default. With it, the typo fails the render. The catch on an umbrella chart is that a subchart's values live under the subchart's name in the parent's values, so setting `additionalProperties: false` at the parent root will reject the `api:` and `worker:` blocks unless the parent schema declares those properties. Declare them, even loosely as objects, and let each subchart's own `values.schema.json` police its interior. Because validation happens after merging, the same constraints also catch a mistyped `--set` key supplied by a deploy job, not just a mistake in a committed file. That is the one place where a schema protects you from an argument nobody reviewed: a job that passes `--set api.replicaCont=11` fails the upgrade instead of quietly deploying the default replica count into production. ## What it cannot do A schema constrains **shape**, never **meaning**. It will happily accept a production file whose hostname still points at staging's fraud-scoring endpoint, whose queue name is the one dev uses, or whose replica count is right for a load test and wrong for Friday afternoon. Those are review problems and smoke-test problems. The schema also cannot tell you that a key present in production is absent from staging — unless you have made it required, in which case the staging render fails and you find out on the pull request. For anything the schema cannot express, the `required` template function is the runtime backstop: `{{ required "api.ingress.host must be set" .Values.api.ingress.host }}` fails the render with a message aimed at the person who forgot, rather than producing an Ingress with an empty host. ## Where it fits in promotion Treat the schema as the contract the environment files are all instances of. It is written once, in the chart, and it is the reason a new environment can be created by copying the schema's requirements rather than copying production's file and deleting the frightening parts. Combined with rendering every environment on every change, it converts 'the prod values file drifted' from an incident into a failed check.
- Which kind of environment drift does the schema not catch?Anything well-formed but wrong: a production file still naming staging's fraud-scoring endpoint, a queue name copied from dev, a replica count that is valid and undersized. It also cannot notice a key that exists only in production unless the schema makes it required, in which case the other environments fail to render. Meaning is a review-and-smoke-test problem; the schema only holds the shape.
- How do you check the production values file before merging, with no production cluster?`helm template charts/fraud-platform -f values/prod.yaml` renders offline and runs schema validation on the way, and `helm lint -f` does the same alongside the chart checks. When you want the API server's opinion on the rendered objects, Helm 4 offers `helm template --dry-run=server`, which replaces the deprecated `--validate` and needs cluster access.
- Does a parent chart's schema validate its subcharts' values?No — each chart's schema validates its own values, and a subchart's schema is enforced against the values that subchart receives. The parent's schema sees the subchart's block as an ordinary property of its own values, which matters when the parent sets `additionalProperties: false`: the subchart keys must be declared as properties there or the render fails before the subchart's own schema is ever consulted.
saying these in an interview costs you the question
- Thinks each -f file is validated on its own
- Expects required to catch keys the defaults supply
- Believes a schema catches a wrong-but-valid hostname
- Only validates the environment being deployed
- Sets additionalProperties false and blocks subchart keys
- Assumes a misspelled key is an error by default