How to Merge Helm Chart Values Per Environment in Python
Merge default Helm chart values with environment-specific overrides using a recursive dictionary merge function, then write each environment's YAML file.
Python code
41 linesfrom pathlib import Path
import json
import tempfile
DEFAULT_VALUES = {
"image": "nginx:latest",
"replicas": 1,
"resources": {"cpu": "100m", "memory": "128Mi"},
}
ENV_OVERRIDES = {
"dev": {"replicas": 1, "resources": {"cpu": "50m"}},
"staging": {"replicas": 2, "resources": {"cpu": "250m", "memory": "256Mi"}},
"prod": {"replicas": 4, "resources": {"cpu": "500m", "memory": "1Gi"}, "image": "nginx:1.21.6"},
}
def merge_values(base: dict, override: dict) -> dict:
result = base.copy()
for key, value in override.items():
if isinstance(value, dict) and isinstance(result.get(key), dict):
result[key] = merge_values(result[key], value)
else:
result[key] = value
return result
def generate_chart_values(env: str) -> dict:
if env not in ENV_OVERRIDES:
raise ValueError(f"Unknown environment: {env}")
return merge_values(DEFAULT_VALUES, ENV_OVERRIDES[env])
if __name__ == "__main__":
with tempfile.TemporaryDirectory() as tmpdir:
for env in ["dev", "staging", "prod"]:
values = generate_chart_values(env)
out_path = Path(tmpdir) / f"values-{env}.yaml"
out_path.write_text(json.dumps(values, indent=2))
print(f"{env}: {out_path} -> {json.dumps(values)}")
Output
dev: /tmp/tmp123456/values-dev.yaml -> {"image": "nginx:latest", "replicas": 1, "resources": {"cpu": "50m", "memory": "128Mi"}}
staging: /tmp/tmp123456/values-staging.yaml -> {"image": "nginx:latest", "replicas": 2, "resources": {"cpu": "250m", "memory": "256Mi"}}
prod: /tmp/tmp123456/values-prod.yaml -> {"image": "nginx:1.21.6", "replicas": 4, "resources": {"cpu": "500m", "memory": "1Gi"}}
How it works
The merge_values function recursively merges two dictionaries: if both the base and override have a dict for the same key, it merges them recursively rather than replacing the entire dict. This allows partial overrides like updating only the CPU in the resources dict while keeping the memory value from the defaults. The generate_chart_values function validates the environment name and then applies the override to the defaults. The script writes each environment's merged values as a JSON file (a stand-in for YAML in this example) inside a temporary directory, which is useful for generating Helm values files during deployment.
Common mistakes
- Using a shallow copy or .update() for nested dicts, which replaces the whole resources dict instead of merging nested keys.
- Forgetting to validate the environment name, leading to silent default values instead of an error.
- Writing YAML as plain text without proper quoting or formatting, which can break Helm parsing.
- Hardcoding file paths instead of using tempfile or a configured output directory.
Variations
- Use PyYAML to actually write YAML files instead of JSON by adding yaml.safe_dump(values).
- Load overrides from separate YAML files per environment instead of a hardcoded dict.
Real-world use cases
- CI/CD pipelines that generate per-environment Helm values files before deploying to dev, staging, and prod clusters.
- Multi-tenant SaaS deployments where each customer or region requires different resource limits and image versions.
- Infrastructure-as-code scripts that need to merge cloud-provider-specific settings with common service defaults.
Sponsored
More from Production deployment patterns
- Auto Rollback on Error Rate Exceeded in Python medium
- Automate Semantic Versioning with Conventional Commits in Python medium
- Design a Data Helper for Beginners in Python easy
- Docker healthcheck CMD mock in Python easy
- Generate a Mock Artifact Version Tag in Python easy
- Generate a docker-compose.yml with mock services in Python easy
Keep learning
Related tutorials and quizzes for this topic.