Values Management
A comprehensive guide to Helm values management covering values.yaml, overrides, environment-specific values, schema validation, and best practices for configuration management.
Helm values are the configuration parameters that customize chart behavior. They allow you to adapt a chart for different environments, use cases, and requirements without modifying the chart itself.
Values flow into templates and determine the final Kubernetes manifests. They are defined in:
values.yaml- Default values in the chart--set- Command-line overrides-f- External values files--values- Multiple values files (merged in order)- Subchart values - Passed from parent to dependencies
values.yaml contains the default values for a chart. It serves as documentation and provides sensible defaults.
# values.yaml - Example with structure
# Global settings
global:
imagePullSecrets: []
storageClass: standard
registry: docker.io
# Application settings
replicaCount: 3
image:
repository: nginx
tag: latest
pullPolicy: IfNotPresent
pullSecrets: []
# Name overrides
nameOverride: ""
fullnameOverride: ""
# Service configuration
service:
type: ClusterIP
port: 80
targetPort: 8080
annotations: {}
# Ingress configuration
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: app.example.com
paths:
- path: /
pathType: Prefix
tls: []
# Resources
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
# Autoscaling
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 80
# Environment
environment: production
# ConfigMap data
configMap:
key1: value1
key2: value2
# Pod settings
podAnnotations: {}
podSecurityContext: {}
securityContext: {}
# Node selector and tolerations
nodeSelector: {}
tolerations: []
affinity: {}
# Persistence
persistence:
enabled: false
storageClass: ""
accessMode: ReadWriteOnce
size: 1Gi
# Extra resources
extraVolumes: []
extraVolumeMounts: []
extraEnv: []
- Organize values logically with clear sections
- Use descriptive keys and comments
- Set sensible defaults for all configurable options
- Document all values in README.md
- Use
globalfor shared configuration - Never store secrets in values.yaml
Values can be overridden at installation or upgrade time using multiple methods.
# Method 1: --set flag (single value)
helm install my-release ./my-chart --set replicaCount=5 --set image.tag=1.25
# Method 2: --set-string (force string)
helm install my-release ./my-chart --set-string service.type=ClusterIP
# Method 3: --set-file (load from file)
helm install my-release ./my-chart --set-file config=config.json
# Method 4: -f (values file)
helm install my-release ./my-chart -f custom-values.yaml
# Method 5: --values (multiple files, merged in order)
helm install my-release ./my-chart \
--values base-values.yaml \
--values env-values.yaml \
--values secret-values.yaml
# Method 6: --set with JSON/YAML
helm install my-release ./my-chart \
--set 'resources={"requests":{"memory":"128Mi"}}'
# Method 7: --set with nested values
helm install my-release ./my-chart \
--set ingress.enabled=true \
--set ingress.hosts[0].host=app.example.com
# Method 8: Using environment variables
export HELM_VALUES_REPLICAS=5
helm install my-release ./my-chart \
--set replicaCount=$HELM_VALUES_REPLICAS
# Upgrade with new values
helm upgrade my-release ./my-chart -f production-values.yaml
--set
-f / --values
Multiple Files
--set-string
- Command-line
--set --valuesfiles (last file has highest priority)values.yamlfrom the chart
Use different values files for different environments (dev, staging, production).
# values-dev.yaml (Development)
replicaCount: 1
image:
tag: dev
environment: development
ingress:
enabled: true
hosts:
- host: dev.example.com
resources:
requests:
memory: "64Mi"
cpu: "100m"
# values-staging.yaml (Staging)
replicaCount: 2
image:
tag: staging
environment: staging
ingress:
enabled: true
hosts:
- host: staging.example.com
resources:
requests:
memory: "128Mi"
cpu: "250m"
# values-prod.yaml (Production)
replicaCount: 5
image:
tag: latest
environment: production
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: app.example.com
tls:
- hosts:
- app.example.com
secretName: app-tls
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1000m"
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
# Install with environment files
helm install my-release ./my-chart -f values-dev.yaml
helm upgrade my-release ./my-chart -f values-staging.yaml
helm upgrade my-release ./my-chart -f values-prod.yaml
# Combine base + environment values
helm install my-release ./my-chart \
-f values-base.yaml \
-f values-dev.yaml
- Maintain separate values files for each environment
- Use a base values file for common settings
- Keep environment-specific overrides minimal
- Don't store secrets in environment values files
- Use CI/CD to apply the correct values file
- Document all environment-specific overrides
values.schema.json provides JSON Schema validation for values.yaml, catching misconfigurations before installation.
# values.schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "Number of replicas for the deployment"
},
"image": {
"type": "object",
"properties": {
"repository": {
"type": "string",
"description": "Container image repository"
},
"tag": {
"type": "string",
"default": "latest",
"description": "Container image tag"
},
"pullPolicy": {
"type": "string",
"enum": ["Always", "IfNotPresent", "Never"],
"default": "IfNotPresent"
}
},
"required": ["repository"]
},
"service": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["ClusterIP", "NodePort", "LoadBalancer"],
"default": "ClusterIP"
},
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535,
"description": "Service port"
}
},
"required": ["port"]
},
"ingress": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": false
},
"hosts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"host": {
"type": "string",
"format": "hostname"
}
},
"required": ["host"]
}
}
}
},
"resources": {
"type": "object",
"properties": {
"requests": {
"type": "object",
"properties": {
"memory": {
"type": "string",
"pattern": "^[0-9]+(Mi|Gi|M|G)$"
},
"cpu": {
"type": "string",
"pattern": "^[0-9]+(m)?$"
}
}
},
"limits": {
"type": "object",
"properties": {
"memory": {
"type": "string",
"pattern": "^[0-9]+(Mi|Gi|M|G)$"
},
"cpu": {
"type": "string",
"pattern": "^[0-9]+(m)?$"
}
}
}
}
}
},
"required": ["image"]
}
- Prevents invalid configurations
- Provides better error messages
- Documents expected values
- Enforces type safety
- Improves developer experience
Global values are accessible from all subcharts. They're defined in the global section of values.yaml.
# Parent chart values.yaml
global:
storageClass: standard
imagePullSecrets:
- name: regcred
registry: docker.io
environment: production
# Subchart uses global values
# In subchart templates
{{ .Values.global.storageClass }}
{{ .Values.global.registry }}/{{ .Values.image.repository }}
# Override global values
helm install my-release ./my-chart \
--set global.storageClass=ssd \
--set global.environment=staging
# Subchart can also have its own values
# Subchart values.yaml
image:
repository: myapp
tag: latest
# Combined with global values
# Final image: {{ .Values.global.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}
- Use global values for shared configuration
- Document global values clearly
- Keep global values minimal
- Use
globalfor registry, storage class, image pull secrets - Override global values at the parent level
values.yaml contains default values. values.schema.json provides JSON Schema validation for values, ensuring they meet the expected format and constraints.postgresql: {postgresqlPassword: secret} overrides values for the postgresql subchart.--set > --values files (later files override earlier) > values.yaml in the chart > default values.--set with sensitive values, or use external secret management tools. Never store secrets in values.yaml files. Use --set or environment variables in CI/CD.global section of values.yaml and are accessible from all subcharts. They're used for shared configuration like registry, storage class, and image pull secrets.values.schema.json for JSON Schema validation. You can also use helm template --dry-run to test values and see the rendered output.--set with environment variables or use a templating tool like envsubst before passing to Helm.helm get values <release> to see the values for an installed release. Use helm get values --all to see all values including defaults.Effective values management is essential for creating flexible and maintainable Helm charts. Use environment-specific values files, schema validation, and clear defaults to make your charts production-ready.