Subcharts in Helm don’t inherit values from their parent chart by default, forcing you to explicitly pass them down.

Let’s say you have a parent chart my-app and a subchart redis. You want to configure the redis subchart’s memory limit from my-app’s values.yaml.

my-app/Chart.yaml

apiVersion: v2
name: my-app
description: A Helm chart for my application
version: 0.1.0
appVersion: 1.0.0
dependencies:
  - name: redis
    version: "16.x.x" # Use a specific version
    repository: "https://charts.bitnami.com/bitnami"

my-app/values.yaml

replicaCount: 1

redis:
  enabled: true
  master:
    persistence:
      size: 8Gi # This is the value we want to pass to the subchart

If you just helm install my-app . with this setup, the redis subchart will use its own default persistence.size. To make my-app’s redis.master.persistence.size control the subchart, you need to map it in the parent chart’s values.yaml.

my-app/values.yaml (modified)

replicaCount: 1

redis:
  enabled: true
  master:
    persistence:
      size: 8Gi # Parent chart's value

# This section maps parent values to subchart values
redis:
  master:
    persistence:
      size: 8Gi # This is the value that will be *used* by the redis subchart

Wait, that looks identical. The trick is how Helm merges values. When you pass values from the parent, they are merged into the subchart’s values. You don’t override the subchart’s values file directly; you provide a new set of values that get merged on top of the subchart’s defaults.

So, the my-app/values.yaml should actually look like this to pass the value down:

my-app/values.yaml (correct)

replicaCount: 1

# This section configures the redis subchart
redis:
  master:
    persistence:
      size: 8Gi

When helm install runs, Helm takes the values from my-app/values.yaml and merges them with the redis subchart’s default values.yaml. The redis section in your parent values.yaml directly corresponds to the structure within the subchart’s values.yaml.

Let’s see this in action. Imagine the redis subchart has a values.yaml like this (simplified):

my-app/charts/redis/values.yaml (simplified subchart defaults)

master:
  persistence:
    enabled: true
    size: 1Gi # Default size

And your parent chart my-app has:

my-app/values.yaml

redis:
  master:
    persistence:
      size: 8Gi # Our desired size

When you run helm install my-app ., Helm does the following:

  1. Loads my-app/values.yaml.
  2. Loads the redis subchart’s default values.yaml.
  3. Merges my-app/values.yaml into the redis subchart’s values. The redis key in the parent’s values becomes the top-level key for merging into the subchart.
  4. The redis.master.persistence.size from my-app/values.yaml (which is 8Gi) overwrites the default size (1Gi) in the subchart’s merged values.

The final set of values used by the redis subchart will effectively be:

master:
  persistence:
    enabled: true
    size: 8Gi # This value came from the parent chart

This allows you to customize any part of a subchart by mirroring its values.yaml structure within your parent chart’s values.yaml.

The key is that the structure in your parent’s values.yaml that corresponds to a subchart must exactly match the path within that subchart’s values.yaml you intend to override. If the subchart’s values.yaml has redis.master.persistence.size, and you want to set it, your parent’s values.yaml needs a redis.master.persistence.size key.

You can also enable or disable subcharts using this mechanism. If the redis subchart has an enabled flag at its root:

my-app/values.yaml

redis:
  enabled: false # This will disable the redis subchart

This works because the redis key in the parent values.yaml is merged into the subchart’s values, and if the subchart’s values.yaml contains an enabled key at the top level, your parent’s value will override it.

The most common pitfall is creating a nested structure in your parent values.yaml that doesn’t align with the subchart’s structure, or forgetting to add the subchart’s name as a top-level key in your parent’s values.yaml when you intend to configure it. For example, if you wanted to configure the redis subchart, and your my-app/values.yaml looked like this:

my-app/values.yaml (incorrect structure for subchart config)

master:
  persistence:
    size: 8Gi

This would not be merged into the redis subchart because there’s no redis key at the top level of my-app/values.yaml to tell Helm "these values are for the redis subchart." Helm expects the key name in the parent’s values.yaml to match the subchart’s name (or whatever alias you might define in Chart.yaml for the dependency).

You can pass global values that apply to multiple subcharts by nesting them under a common key in your parent’s values.yaml, and then referencing that common key within the specific subchart configurations.

my-app/values.yaml

global:
  storageClass: "my-fast-ssd"
  replicaCount: 3

redis:
  master:
    persistence:
      size: 8Gi

      storageClass: {{ .Values.global.storageClass }} # Reference global value


nginx:

  replicaCount: {{ .Values.global.replicaCount }} # Reference global value

Here, global is a special key that Helm processes. Values under global are made available to all subcharts via the .Values.global context. This is distinct from simply passing values directly to a subchart.

The next thing you’ll bump into is managing complex conditional logic for subcharts based on these passed values.

Want structured learning?

Take the full Helm course →