global. values are passed to all subcharts automatically. Non-global subchart values must be nested under the subchart's name key. Example: postgresql.auth.database configures the postgresql subchart's auth.database value.
Dependencies & Subcharts
Include third-party charts (PostgreSQL, Redis, etc.) as dependencies, manage subcharts, and use global values.
🧒 Simple Explanation (ELI5)
Imagine building a house. You don't manufacture the plumbing, electrical wiring, and appliances yourself — you buy them from specialists and integrate them. Helm dependencies work the same way: your app chart imports pre-built charts (PostgreSQL, Redis, NGINX) and configures them through values.
🔧 Technical Explanation
Declaring Dependencies
# Chart.yaml
apiVersion: v2
name: myapp
version: 1.0.0
dependencies:
- name: postgresql
version: "12.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled # Toggle on/off
- name: redis
version: "17.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
- name: common
version: "2.x.x"
repository: "https://charts.bitnami.com/bitnami"
tags:
- infrastructure
Dependency Commands
# Download dependencies (creates charts/ dir with .tgz files) helm dependency update ./myapp # List dependencies and their status helm dependency list ./myapp # Rebuild from Chart.lock (reproducible builds) helm dependency build ./myapp
Configuring Subchart Values
# values.yaml of parent chart
# Subchart values go under a key matching the subchart name
postgresql:
enabled: true
auth:
postgresPassword: "secretpass"
database: myappdb
primary:
resources:
requests:
cpu: 250m
memory: 256Mi
redis:
enabled: true
architecture: standalone
auth:
enabled: false
Global Values
# values.yaml
global:
imageRegistry: myregistry.azurecr.io
storageClass: managed-premium
# In ANY template (parent or subchart):
image: {{ .Values.global.imageRegistry }}/myapp:v1
# Both parent and subcharts can access .Values.global
condition vs tags
| Feature | condition | tags |
|---|---|---|
| Scope | Single dependency | Group of dependencies |
| How | condition: postgresql.enabled | tags: [backend] |
| Override | --set postgresql.enabled=false | --set tags.backend=false |
| Priority | condition overrides tags | tags are checked if condition is absent |
Chart.lock
Chart.lock is auto-generated by helm dependency update. It records exact resolved versions (like package-lock.json). Use helm dependency build in CI/CD to get the exact same versions without re-resolving.
Chart.lock Workflow in Practice
# Developer workflow: # 1. Change a dependency version in Chart.yaml vim Chart.yaml # Update postgresql from 12.x.x to 13.x.x # 2. Re-resolve dependencies (updates Chart.lock + downloads .tgz) helm dependency update . # 3. COMMIT BOTH Chart.yaml AND Chart.lock to Git git add Chart.yaml Chart.lock git commit -m "chore: upgrade postgresql subchart to 13.x.x" # CI/CD workflow (reproducible): # Use 'build' (not 'update') to install from the lockfile exactly helm dependency build . # ↑ This uses Chart.lock to get the EXACT same versions # If Chart.lock is missing or out of date, 'build' fails
Just like you commit package-lock.json, always commit Chart.lock. Without it, helm dependency update in CI might resolve a different version than what you tested locally (e.g., if a new patch was published). This can introduce bugs silently.
Version Pinning Strategies
| Strategy | Chart.yaml | Risk | When to Use |
|---|---|---|---|
| Exact pin | version: "12.12.10" | Miss security patches | Production charts, strict reproducibility |
| Patch range | version: "12.12.x" | Low — patches only | Balanced: get fixes, avoid breaking changes |
| Minor range | version: "12.x.x" | Medium — new features possible | Development, internal charts |
| Major range | version: ">=12.0.0" | High — breaking changes possible | Almost never in production |
⌨️ Hands-on
# Create a chart with a PostgreSQL dependency
helm create depslab
cd depslab
# Add dependency to Chart.yaml
cat >> Chart.yaml <<EOF
dependencies:
- name: postgresql
version: "12.12.10"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
EOF
# Add subchart values to values.yaml
cat >> values.yaml <<EOF
postgresql:
enabled: true
auth:
postgresPassword: "demopass"
database: depslab_db
EOF
# Download the dependency
helm dependency update .
# Verify
ls charts/ # Should show postgresql-12.12.10.tgz
helm dependency list .
# Render to see all resources (parent + subchart)
helm template test . | grep "kind:" | sort | uniq -c
# Install with dependency
helm install depslab . -n demo --create-namespace
# Disable the dependency
helm upgrade depslab . -n demo --set postgresql.enabled=false
# Cleanup
helm uninstall depslab -n demo
🐛 Debugging Scenarios
Scenario 1: "Error: no repository definition for bitnami"
# You need to add the repo first helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update # Then update dependencies helm dependency update ./mychart
Scenario 2: Subchart values not being applied
# Values for subcharts must be nested under the subchart name
# WRONG:
auth:
database: mydb # Parent chart's auth, NOT postgresql's
# RIGHT:
postgresql:
auth:
database: mydb # Goes to postgresql subchart
# Verify what gets passed:
helm template test . | grep -A 10 "kind: Secret"
Scenario 3: Version conflict
# "Error: chart requires postgresql >= 12.0.0, found 11.9.0" # Check current lock: cat Chart.lock # Fix: Update the version range in Chart.yaml # Then re-resolve: helm dependency update .
Scenario 4: Subchart upgrade introduced breaking changes
# After running helm dependency update, your chart breaks # because the subchart changed its values schema # Step 1: Check what version changed diff <(git show HEAD:Chart.lock) Chart.lock # Shows: postgresql went from 12.12.10 to 13.1.0 # Step 2: Check the subchart's changelog/release notes helm show chart bitnami/postgresql --version 13.1.0 # Step 3: Rollback — restore the old lockfile git checkout Chart.lock helm dependency build . # Reinstall old versions # Step 4: Fix forward (when ready) # Read migration guide, update values.yaml for new schema # Example: auth.postgresPassword → auth.password (Bitnami change) # Test: helm template test . | grep postgres # Then: helm dependency update . → commit both files
Each subchart creates its own Kubernetes resources (Deployments, Services, PVCs). When you helm install a chart with PostgreSQL as a dependency, you get a full PostgreSQL StatefulSet, Service, and PersistentVolumeClaim in your namespace. Run kubectl get all -n <ns> after install to see everything — not just your app's pods. Understanding this is critical for debugging: if your app can't connect to the database, check the subchart's pods and services, not just your own.
🎯 Interview Questions
Beginner
A subchart is a chart included as a dependency of another chart. It lives in the parent chart's charts/ directory (as a .tgz archive). Example: your app chart depends on a PostgreSQL subchart. When you install the parent, both the app and PostgreSQL are deployed together.
In Chart.yaml under the dependencies: key. Specify name, version, and repository. Then run helm dependency update to download the subchart into charts/. Use condition to make it optional.
Auto-generated lockfile that records the exact resolved versions of all dependencies. Like package-lock.json in Node.js. Use helm dependency build to install from the lockfile (reproducible). helm dependency update re-resolves and updates the lockfile.
Nest values under a key matching the subchart name. If subchart is "postgresql", put values under postgresql: in the parent's values.yaml. Example: postgresql.auth.database: mydb. Global values (global:) are automatically available in all subcharts.
Values under the global: key are shared with all subcharts. Accessible via .Values.global.key in any template (parent or subchart). Used for cross-cutting concerns: image registry, storage class, domain name.
Intermediate
condition toggles a single dependency: condition: postgresql.enabled. tags groups multiple dependencies: tags: [backend] — all dependencies with the "backend" tag are toggled together. Condition takes priority over tags if both are set.
A chart with no templates of its own, only dependencies. Used to deploy a complete application stack (app + database + cache + monitoring) with one helm install. The umbrella chart's values.yaml configures all subcharts. Common in microservices architectures for deploying an entire environment.
A chart with type: library in Chart.yaml. It contains only helper templates (_helpers.tpl), no manifest templates. Cannot be installed directly — used as a dependency to share common template patterns. Example: Bitnami's "common" chart provides shared label generators, name truncation, etc.
No. Values flow top-down: parent chart's values override subchart defaults. A subchart cannot access or modify the parent's values. It can only access its own values and .Values.global. This is by design — the parent is in control.
helm install will fail with "found in Chart.yaml, but missing in charts/ directory". Always run helm dependency update (or build) before install/package. In CI/CD, include it as a build step.
Scenario-Based
In Chart.yaml: both as dependencies with conditions. condition: postgresql.enabled and condition: redis.enabled. In values-dev.yaml: redis.enabled: false. In values-prod.yaml: redis.enabled: true. PostgreSQL is enabled by default in values.yaml.
Use global values: global.imageRegistry: myregistry.azurecr.io. Both subcharts access it via .Values.global.imageRegistry. This is the exact use case globals are designed for — cross-cutting configuration shared across all charts in the dependency tree.
Create a library chart with shared named templates. Each microservice chart depends on the library chart and uses {{ include "baselib.deployment" . }}. Or create a base application chart that all services use as a dependency, overriding only the values. Publish to an internal chart repo.
1) Rollback: helm rollback <release>. 2) Pin the subchart version in Chart.yaml to the last working version. 3) Run helm dependency update. 4) Read the subchart's changelog for migration instructions. 5) Update your values to match the new schema. 6) Test with helm template and helm upgrade --dry-run. 7) Use Chart.lock for reproducible builds.
Create an umbrella chart with all services as dependencies (each as a subchart). Each subchart has its own templates. The umbrella's values.yaml configures all services. helm install mystack ./umbrella -f values-prod.yaml deploys everything. Alternative: use Helmfile for multi-release management without umbrella chart complexity.
🌍 Real-World Use Case
A data analytics platform uses an umbrella chart for its full stack:
- Parent chart:
analytics-platform(umbrella) - Subcharts: PostgreSQL (Bitnami), Redis (Bitnami), Kafka (Bitnami), custom API chart, custom UI chart
- Global values: shared domain, image registry, storage class
- Environment promotion: values-dev.yaml → values-staging.yaml → values-prod.yaml
- One
helm upgrade --installdeploys or updates the entire platform
📝 Summary
- Dependencies are declared in
Chart.yamland downloaded withhelm dependency update - Subchart values are nested under the subchart name key in parent values.yaml
global:values are shared with all subcharts automaticallyconditiontoggles individual dependencies;tagstoggle groups- Umbrella charts combine multiple subcharts for full-stack deployment