What makes a Helm chart's values.yaml defaults safe to install unedited?
answer
- The command a stranger runs first
- No -f file, no --set
- Absent is not the same as empty
- Neutral, modest, unprivileged
- required fails the render, not the pod
basics
~20 sDefaults that render runnable YAML with no -f file: every key a template reads is present and typed, empty extension points declared as {} or [], nothing secret or site-specific baked in, and required inputs failing the render loudly.
solid answer
~50 s`helm install` with no `-f` and no `--set` is the first thing a stranger does with your chart, so `values.yaml` has to be a working configuration rather than a form to fill in. Every path a template dereferences must exist and hold the right type: declare empty extension points explicitly (`podAnnotations: {}`, `tolerations: []`) instead of leaving them implicit, because a missing intermediate map aborts the render with a nil-pointer error. Defaults must be environment-neutral - no internal hostnames, no registry outsiders cannot pull from, no password sitting in a values file. Where there is no honest default, such as an endpoint only the installer knows, keep the key present but empty and wrap the read in Helm's `required` function so the render fails with a readable message instead of installing something broken. Keep the unedited footprint small, unprivileged and single-replica-cheap so trying the chart on a shared cluster is safe.
code
yaml · 16 linesreplicaCount: 1
image:
repository: registry.example.com/platform/reranker
tag: "1.9.3"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 8080
resources: {}
podAnnotations: {}
nodeSelector: {}
tolerations: []
reranker:
candidatePoolSize: 384
# No default: the feature store lives outside the chart.
featureStoreUrl: ""go deeper
Be ready to say what helm install uses when no values file is passed, and to name two things that must never sit in values.yaml: credentials and site-specific hostnames. Knowing that empty maps and lists are written out explicitly already puts you ahead.
Explain the mechanics: which missing-key cases render empty and which abort with a nil-pointer error, why {} differs from a bare key, and what Helm's required function does to a render versus what a default supplies.
Show the operational judgement - defaults are a blast-radius decision. Talk about unprivileged, single-replica, no-load-balancer defaults, and about the CI step that renders the chart with no values at all so a defaults defect never reaches a consumer.
Own the policy: which of your charts' defaults are opinions the platform is willing to support forever, how a default differs from a guarantee that should not be configurable at all, and how you keep environment-specific values out of charts organisation-wide.
### values.yaml is the chart's default configuration, not its documentation A Helm chart is a directory of templates plus `values.yaml`. When someone runs `helm install rr ./reranker` with no other input, Helm merges nothing on top: the templates render against exactly what `values.yaml` contains. That makes the file the chart's default configuration, and the unedited install the path most people take first - when they evaluate the chart, when they run it in a scratch namespace, and when CI renders it to check a change. If that path produces broken YAML, an image nobody outside your network can pull, or a workload that demands cluster-admin, the chart has failed before anyone has read a template. ### Rule one: every path a template reads must exist Helm renders with Go text/template, and the failure modes for missing keys are asymmetric. Reading a key that is absent from a map that *does* exist yields an empty value, which usually renders as a blank field. Reading through a map that is itself absent is fatal: if `values.yaml` has no `metrics` key at all, `{{ .Values.metrics.port }}` aborts with `nil pointer evaluating interface {}.port`. So the whole shape of the values tree should be written out, including the parts that are empty. A block like ```yaml podAnnotations: {} nodeSelector: {} tolerations: [] extraEnv: [] ``` costs four lines and removes an entire class of report. It also documents the type: `{}` tells a reader the key is a map and `[]` tells them it is a list, which matters because they will be pasting YAML into it. Writing `podAnnotations:` with nothing after it makes the value null, which is not the same as an empty map and behaves differently once a template tries to range over it. ### Rule two: defaults must be environment-neutral A default that only works inside your company is not a default. That means no internal registry mirror, no cluster-local DNS name for a database, no bucket name, and above all no credential. A values file travels with the chart into a public repository, into a packaged tarball, into every checkout of the repo that vendors it; treating it as a place to park a token is the single worst thing you can do to a chart. The neutral choices are a publicly pullable image reference, an in-chart Service name for anything the chart itself deploys, and an empty string for anything external. ### Rule three: no honest default means fail loudly, not plausibly Some inputs genuinely have no sensible default - the endpoint of a feature store, a licence key, the hostname an Ingress should answer on. The wrong fix is a plausible placeholder, because a placeholder installs successfully and then fails at runtime, in a pod log, at whatever hour someone notices. The right fix is a key present in `values.yaml` with an empty value and a comment, plus `{{ required "reranker.featureStoreUrl must be set" .Values.reranker.featureStoreUrl }}` in the template. `required` is one of the functions Helm adds on top of sprig; it aborts `helm install`, `helm upgrade` and `helm template` with your message and nothing is created. The candidate who knows this also knows the cost: `required` fires on every render, so it makes an unedited `helm template` fail, which is a deliberate trade - a chart that cannot render without an input is telling you so at the earliest possible moment. ### Rule four: the unedited install should be modest Defaults are also a security and capacity statement. One replica rather than nine, no `hostNetwork`, no privileged container, no cluster-scoped RBAC unless the chart's whole purpose is cluster-scoped, and a service type that does not silently provision a public load balancer and a bill. `helm create` models this: it ships `resources: {}` with commented suggestions rather than guessing numbers, precisely because the right requests depend on the cluster, and it leaves autoscaling disabled. Where you do pick a number, pick one that is obviously a starting point and say so in a comment next to it. ### How this is checked The cheap check is mechanical and belongs in CI: render the chart with no values at all and assert the output parses. Then render it again with each documented example values file. Most defaults defects - a missing intermediate map, a null where a list was meant, an indentation break from an empty block - surface in that first render, long before a cluster is involved.
- A template reads .Values.metrics.port but values.yaml has no metrics key at all. What happens?The render aborts. One missing level is survivable - reading an absent key from a map that exists yields an empty value - but with `metrics` absent, `.Values.metrics` is nil and dereferencing `.port` on nil fails with `nil pointer evaluating interface {}.port`. Declaring the parent map in values.yaml, even as `metrics: {}`, prevents it, which is why authors write empty structures out rather than leaving them implicit.
- Should a chart ship default CPU and memory requests?`helm create` deliberately does not: it ships `resources: {}` with commented suggestions, because the right numbers depend on the cluster and a wrong default is worse than none. For a chart you operate yourself, shipping measured requests is reasonable and helpful. For a chart strangers install, leave them empty, comment realistic starting values, and expect the cluster to supply its own floor.
- Is it acceptable to ship a placeholder like a dummy password so the chart installs cleanly?No. A placeholder converts a render-time failure into a runtime one, and a shipped default credential has a way of surviving into production. Keep the key present and empty for discoverability, wrap the template read in `required` so install stops with a readable message, and let the installer supply the real value through their own mechanism.
values.yaml is the floor model in the showroom: it has to switch on and work as it stands, not sit there with a note saying the customer supplies the power cable.
saying these in an interview costs you the question
- Assumes everyone passes a -f file, so defaults never actually render
- Omits an intermediate map and lets the template dereference nil
- Ships an internal registry host, hostname or password as a default
- Uses a plausible placeholder that installs but fails at runtime
- Writes a bare key with no value, producing null instead of an empty map
- Treats values.yaml as documentation rather than the real defaults