How do you manage environment-specific configuration with Helm?

6 minintermediatehelm-valuesenvironment-configuration

Quick Answer

Maintain a base `values.yaml` with sensible defaults, and create separate, smaller values files per environment (`values-dev.yaml`, `values-production.yaml`) containing only the values that actually differ — passed at install/upgrade time with `--values` (which can be supplied multiple times, later files overriding earlier ones), or individual overrides via `--set` for quick one-off changes. This keeps environment differences explicit and minimal, without duplicating the entire configuration or the chart's templates per environment.

Detailed Answer

Layering values files

# values.yaml -- the chart's baseline defaults
replicaCount: 2
image:
  repository: myapp
  tag: "1.0.0"
resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
autoscaling:
  enabled: false
# values-production.yaml -- ONLY the values that differ from the defaults
replicaCount: 6
resources:
  requests:
    cpu: "500m"
    memory: "512Mi"
autoscaling:
  enabled: true
  minReplicas: 6
  maxReplicas: 20
helm install my-app ./mychart -f values.yaml -f values-production.yaml

Helm merges values files in the order given, with later files overriding earlier ones for any key they both specify — so values-production.yaml only needs to contain the handful of keys that genuinely differ for production, not a full duplicate copy of every setting.

Quick one-off overrides with --set

helm upgrade my-app ./mychart -f values-production.yaml --set image.tag=2.1.0

--set is convenient for a single, temporary override (like bumping just the image tag as part of a CI/CD pipeline step) without needing to edit or generate a values file — but it's harder to track/audit than a values file checked into version control, so it's generally better suited to programmatic use (a deploy script substituting in a build-specific value) than for hand-maintained, meaningful configuration differences.

A common project layout

mychart/
├── values.yaml                  # defaults
environments/
├── values-dev.yaml
├── values-staging.yaml
└── values-production.yaml

Keeping environment-specific values files outside the chart itself (rather than bundled inside it) is a common pattern, since it cleanly separates "what the chart is" (reusable, environment-agnostic templates and sensible defaults) from "how a specific environment configures it" (which changes far more often and is often owned/reviewed by a different part of the team, like a platform/SRE group rather than the application developers who own the chart's templates).

Secrets shouldn't live in plain values files

Values files are ordinary, unencrypted text — genuinely sensitive values (database passwords, API keys) shouldn't be committed directly in a values-production.yaml any more than they should in a raw Kubernetes Secret manifest (see the security topic's Secrets question). Common approaches: reference an already-existing Kubernetes Secret (created out-of-band, via an external secrets manager) from the chart's templates rather than passing the actual secret value through values.yaml at all, or use a values-file encryption tool (like helm-secrets, built on SOPS) so sensitive values files themselves can be safely committed in encrypted form.

Validating what will actually be applied, before applying it

helm template my-app ./mychart -f values-production.yaml

helm template renders the final Kubernetes manifests locally without installing anything — an essential sanity check before running a real helm upgrade against production, letting you review the exact resulting YAML (confirming the right image tag, replica count, resource limits actually got substituted correctly) rather than trusting the values-merging logic blindly.

Keep the base values.yaml as the single source of sensible, safe defaults; keep per-environment files minimal (only the actual deltas); use --set sparingly and mainly for CI/CD-driven, single-value substitutions; and never commit real secret values into any values file, encrypted or not, without a specific reason.

Related Resources