TL;DR

Values are the chart's configuration API. Use environment-specific files in Git, render before applying, diff against the live release, and roll back via helm history when something breaks.

Values Precedence

Later sources override earlier ones. When debugging "why did my value not apply?", walk this list bottom-up.

  1. Chart values.yaml defaults.
  2. Parent chart values passed to subcharts.
  3. User-supplied files from -f, in the order given.
  4. --set, --set-string, and --set-file (highest priority).

Environment Overlays

FilePurpose
values.yamlSafe defaults committed in the chart
values-dev.yamlLower replicas, debug logging, internal URLs
values-staging.yamlProd-like sizing, staging ingress host
values-prod.yamlProduction replicas, resources, ingress, PDBs
bash multi-file.sh
# Later files override earlier ones.
helm upgrade --install web-api ./chart -n app \
  -f values.yaml \
  -f values-prod.yaml \
  --set image.tag="${GIT_SHA}"

Production Values Shape

This values file shows the kind of knobs you normally expose for production: replicas, image, service, resources, ingress, globals, and app env. Use it as a starting shape, then remove options the client does not support.

yaml values-prod.yaml
replicaCount: 4

image:
  repository: registry.example.com/platform/web-api
  tag: "abc123f"   # Immutable commit SHA or digest — never "latest" in prod.

service:
  type: ClusterIP
  port: 80
  targetPort: 8080

resources:
  requests:
    cpu: 250m
    memory: 256Mi
  limits:
    cpu: "1"
    memory: 512Mi

ingress:
  enabled: true
  className: nginx
  host: api.example.com

# Passed to subcharts via global key.
global:
  environment: prod
  storageClass: gp3

env:
  LOG_LEVEL: info

--set Overrides

Use --set for small temporary overrides and CI-injected values such as image tags. Prefer values files for stable environment config, and use --set-string when a numeric-looking value must remain a string.

bash set-overrides.sh
# --set coerces types; use --set-string for IDs and version strings.
helm upgrade web-api ./chart -n app \
  --set replicaCount=6 \
  --set-string image.tag="1.2.3" \
  --set ingress.enabled=true

# Inject a secret file without committing it to Git.
helm upgrade web-api ./chart -n app \
  --set-file config.json=./secrets/config.json

# Override a subchart value (postgresql is the subchart name).
helm upgrade web-api ./chart -n app \
  --set postgresql.auth.password="${DB_PASSWORD}"

Safe Upgrade Workflow

This is the safer operator flow for changing a Helm release: update dependencies, lint, render, diff, upgrade with wait/atomic, then verify history. Use it for client environments where rollback must be quick and auditable.

bash helm-upgrade.sh
helm dependency update ./chart
helm lint ./chart
helm template web-api ./chart -n app -f values-prod.yaml > /tmp/rendered.yaml

# Install helm-diff plugin: helm plugin install https://github.com/databus23/helm-diff
helm diff upgrade web-api ./chart -n app -f values-prod.yaml

helm upgrade --install web-api ./chart -n app \
  -f values-prod.yaml \
  --atomic \
  --wait \
  --timeout 10m

helm history web-api -n app
helm rollback web-api <revision> -n app --wait --timeout 10m

Debugging Releases

Use these commands when you need to understand what Helm believes it installed and how that compares to live Kubernetes objects. They are especially useful after a failed upgrade or unexpected drift.

bash helm-debug.sh
helm list -A
helm status web-api -n app
helm get values web-api -n app --all       # Effective values including --set overrides.
helm get manifest web-api -n app           # Last applied Kubernetes YAML.
helm get notes web-api -n app              # Post-install NOTES.txt output.

# Compare live cluster vs what Helm thinks it deployed.
kubectl get deploy,svc,ingress -n app -l app.kubernetes.io/instance=web-api
kubectl get events -n app --sort-by=.lastTimestamp | tail -n 50

Uninstall

Use uninstall only when the release truly should be removed. Check PVCs, cloud resources, hooks, and finalizers first, because uninstalling a chart can delete Kubernetes objects while leaving external dependencies behind.

bash uninstall.sh
helm uninstall web-api -n app
helm uninstall web-api -n app --keep-history   # Keep release history for audit.
helm list -A --pending                           # Find stuck pending-uninstall releases.

Quick Fixes

SymptomCheck
Value not appliedhelm get values <release> --all — confirm precedence
Upgrade changed nothingChart version unchanged; verify image.tag in rendered output
Subchart config ignoredUse subchart name prefix: postgresql.auth.password
Manual kubectl edit revertedExpected — next Helm upgrade restores chart state

Gotchas

  • !--set typing: use --set-string for account IDs, versions, and numeric strings Helm would coerce to numbers.
  • !--atomic is not magic: it rolls back Kubernetes resources, not external side effects like DB migrations.
  • !Drift: manual kubectl edit changes are overwritten on the next upgrade unless the client uses a drift-tolerant GitOps policy.
  • !Null vs empty: setting a value to null in YAML removes the key; an empty string may still render in templates.