Skip to content
7 min read·Lesson 5 of 8

Dependencies and Umbrella Charts

Composing applications from charts: declaring dependencies, the charts/ folder, conditions and tags, alias, and the umbrella pattern.

Real applications are rarely one component. They have a database, a cache, a message broker, a worker pool. Helm lets you compose charts hierarchically — though, as we will see, this power is easy to overuse.

Declaring Dependencies

Add them to Chart.yaml:

apiVersion: v2
name: my-app
version: 1.4.2
dependencies:
  - name: postgresql
    version: "13.x.x"
    repository: "oci://registry-1.docker.io/bitnamicharts"
    condition: postgresql.enabled

  - name: redis
    version: "18.x.x"
    repository: "oci://registry-1.docker.io/bitnamicharts"
    condition: redis.enabled
    alias: cache              # rename inside our chart

  - name: common-lib
    version: "2.0.0"
    repository: "oci://ghcr.io/acme/charts"
    import-values:
      - child: globalDefaults
        parent: defaults

Then resolve and download:

helm dependency update ./my-app
ls my-app/charts
# common-lib-2.0.0.tgz  postgresql-13.4.1.tgz  redis-18.7.0.tgz

helm dependency list ./my-app
helm dependency build ./my-app    # uses Chart.lock; for reproducible builds in CI

The Chart.lock file records exact versions resolved. Commit it. Use helm dependency build in CI to install the locked versions (analogous to npm ci).

How Sub-Chart Values Work

The parent's values.yaml contains one key per sub-chart, named after the dependency (or its alias):

# Parent values.yaml
replicaCount: 3

postgresql:
  enabled: true
  auth:
    database: myapp
    username: myapp
  primary:
    persistence:
      size: 20Gi

cache:                # alias of 'redis'
  enabled: true
  architecture: standalone
  auth:
    enabled: false

Inside the sub-chart's templates, the same data appears under .Values directly — the parent's key is stripped. A sub-chart never knows it's a sub-chart.

Global Values

The reserved key global in parent values is shared with every sub-chart:

# Parent
global:
  storageClass: gp3
  imageRegistry: ghcr.io/acme

postgresql:
  primary:
    persistence: { size: 20Gi }   # storageClass inherited from global

In the sub-chart, access via .Values.global.storageClass. Use sparingly — globals are easy to abuse and create implicit coupling.

Conditions and Tags

condition on a dependency points to a values key that turns the sub-chart on or off:

dependencies:
  - name: postgresql
    condition: postgresql.enabled
  - name: redis
    condition: cache.enabled
    alias: cache

tags are a coarser switch — enable several dependencies with one toggle:

dependencies:
  - name: postgresql
    tags: [persistence]
  - name: redis
    tags: [persistence, cache]

# values.yaml
tags:
  persistence: false   # disables both

The condition wins over tags when both are set.

The Umbrella Chart Pattern

An "umbrella chart" is one with no templates of its own (or only a few utility templates) and many dependencies. Its purpose is to deploy a coherent stack — say, a full observability platform — with one helm install:

observability-stack/
├── Chart.yaml      # dependencies: prometheus, grafana, loki, tempo, alertmanager
├── values.yaml     # composed configuration for all five
└── templates/
    └── _helpers.tpl

Trade-offs:

  • Pros: single source of truth for the stack; one upgrade path; environment differences expressed in one values file.
  • Cons: a change in any sub-chart blocks the whole upgrade; debugging crosses chart boundaries; values surface for the umbrella is huge.

Library Charts

A library chart (type: library in Chart.yaml) has no rendered resources — only named templates exposed for reuse. The chart is added as a dependency; its helpers become available via include:

{{ include "common-lib.deployment" . }}
{{ include "common-lib.labels" . }}

Useful for organisations standardising on consistent label sets, security contexts, or pod templates across many internal charts.

When NOT to Use Dependencies

Sub-charts couple lifecycles. A bad upgrade in PostgreSQL drags your app's chart with it. Common alternatives:

  • Separate releases. Install PostgreSQL once; install the app chart with a values pointer at the existing database. Independent upgrade cadence, clearer ownership.
  • Operators. For stateful services (Postgres, Kafka, Elasticsearch), a CNCF operator (CrunchyData, Strimzi, ECK) is almost always better than a stateful Helm chart.
  • GitOps composition. An Argo CD Application per chart; a parent App-of-Apps orchestrates. The composition lives in Git, not in YAML embedded in a chart.

The Right Mental Model

Use Helm dependencies for tightly-coupled sidecars and library helpers. Use separate releases or operators for anything stateful or independently versioned. Use GitOps to orchestrate the whole.

Key Takeaways

  • Dependencies are declared in Chart.yaml and resolved with helm dependency update.
  • Sub-charts receive values under a key matching their name (or alias).
  • condition and tags allow consumers to enable/disable sub-charts.
  • Umbrella charts compose multiple sub-charts into a single deployable unit.
  • Avoid deep dependency trees in production — prefer flat composition or GitOps orchestration.

Test your knowledge

Try exam-style practice questions to reinforce what you've learned.

Practice Questions →