Helm Charts Explained
Understand Helm charts, their structure, templates, values, releases, dependencies, and how Helm simplifies deploying applications to Kubernetes.
Helm is a package manager and templating tool for Kubernetes. It allows developers and platform teams to package Kubernetes manifests into reusable charts, configure them with values, and install or upgrade applications as managed releases.
Without Helm, deploying an application to Kubernetes often means maintaining multiple YAML manifests and manually changing configuration between environments. Helm introduces templates and values so the same chart can be reused for development, staging, production, and other environments without duplicating every manifest.
This guide explains what Helm charts are, how their directory structure works, how templates and values are combined, what Helm releases represent, how to install and upgrade charts, how dependencies work, and how to design maintainable charts for real Kubernetes applications.
What Is Helm?
Helm is a tool for managing applications deployed to Kubernetes. It packages Kubernetes resource definitions into charts and provides commands for installing, upgrading, inspecting, and removing those applications.
A Helm chart can contain Kubernetes resources such as Deployments, Services, ConfigMaps, Secrets, Ingress resources, ServiceAccounts, and other manifests. Instead of storing every environment-specific value directly in those manifests, a chart can expose configurable values through values.yaml and Helm's template system.
helm version
helm repo list
helm search repo nginxHelm commands are typically executed from a developer workstation, CI/CD system, or other environment that has access to the target Kubernetes cluster.
What Is a Helm Chart?
A Helm chart is a directory containing files that describe a Kubernetes application and its configuration. A chart normally includes metadata, default values, templates, and optionally chart dependencies and other supporting files.
A chart is not itself a running application. It is a package or template definition from which Helm can generate Kubernetes manifests and create a release in a cluster.
my-app/
├── Chart.yaml
├── values.yaml
├── charts/
├── templates/
└── templates/NOTES.txtThe exact contents can vary. A chart can also contain files such as README documentation, a values.schema.json file for values validation, and other chart metadata.
Helm Chart Directory Structure
| Path | Purpose |
|---|---|
| Chart.yaml | Chart metadata such as name and version |
| values.yaml | Default configuration values |
| templates/ | Kubernetes manifest templates |
| charts/ | Chart dependencies |
| templates/NOTES.txt | Post-install and post-upgrade usage information |
| values.schema.json | Optional schema for validating values |
| README.md | Optional chart documentation |
The templates directory contains the files that Helm processes to produce Kubernetes manifests. Chart.yaml describes the chart itself, while values.yaml provides default configuration that templates can consume.
Chart.yaml
Chart.yaml is the main metadata file for a Helm chart. It identifies the chart and can contain information such as its version, application version, description, and dependencies.
apiVersion: v2
name: my-app
description: A Helm chart for a Kubernetes application
type: application
version: 1.0.0
appVersion: "2.4.1"The chart version describes the version of the chart package itself. appVersion is commonly used to describe the version of the application being deployed. These values serve different purposes and should not automatically be treated as the same version.
Chart Version vs Application Version
Helm charts have their own versioning. A chart may change because its templates, defaults, or deployment behavior changed even when the application version stays the same.
| Version | Meaning |
|---|---|
| version | Version of the Helm chart |
| appVersion | Version of the application represented by the chart |
For example, a chart might have version 3.2.0 while deploying application version 5.1.0. Updating the chart's resource configuration can require a chart version change without changing the application binary.
values.yaml
values.yaml contains default configuration values for a chart. Templates can reference these values using Helm's template syntax.
replicaCount: 2
image:
repository: nginx
tag: "1.27"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
resources: {}The values file can describe image settings, replica counts, service configuration, resource requests and limits, ingress settings, environment variables, persistence, and other application options.
Helm Templates
Helm templates are Kubernetes manifest files containing Go template expressions and Helm-provided functions. Helm processes these files and substitutes values before sending the resulting manifests to Kubernetes.
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-web
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}-web
template:
metadata:
labels:
app: {{ .Release.Name }}-web
spec:
containers:
- name: web
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"Expressions such as .Values.replicaCount read values from values.yaml, while .Release.Name provides information about the current Helm release.
How Helm Values Reach Templates
When Helm renders a chart, it combines the chart's default values with values supplied by the user or deployment system. Templates access the resulting configuration through .Values.
replicaCount: 3
image:
repository: my-company/web
tag: "2.0.0"spec:
replicas: {{ .Values.replicaCount }}
containers:
- name: web
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"This separation allows the Kubernetes resource definition to remain mostly unchanged while configuration varies between installations.
Overriding Helm Values
Default values can be overridden when installing or upgrading a chart. A common approach is using a separate YAML file.
replicaCount: 5
image:
tag: "2.1.0"
service:
type: LoadBalancerhelm install my-app ./my-app -f production-values.yamlThe -f or --values option supplies additional values. Multiple values files can be provided when a deployment workflow needs layered configuration.
helm upgrade my-app ./my-app \
-f values.yaml \
-f production-values.yamlLater values files can override values defined earlier, allowing a base configuration to be combined with environment-specific settings.
Setting Values With --set
Individual values can also be supplied directly with --set.
helm install my-app ./my-app \
--set replicaCount=3 \
--set image.tag=2.1.0The --set option is convenient for small overrides and automation, but complex configuration is usually easier to review and maintain in a YAML values file.
Helm Value Precedence
Helm combines configuration from multiple sources. The chart's values.yaml provides defaults, while supplied values files and command-line overrides can replace those defaults.
A useful practical model is that more specific configuration overrides less specific defaults. This allows a chart to provide sensible defaults while deployment environments supply their own configuration.
helm upgrade my-app ./my-app \
-f values.yaml \
-f staging.yaml \
--set image.tag=2.2.0When debugging a deployment, inspect the values Helm actually used rather than looking only at the chart's default values.yaml.
Rendering a Helm Chart Locally
helm template renders a chart into Kubernetes manifests without installing it into a cluster. This is one of the most useful commands for developing and debugging charts.
helm template my-app ./my-app
helm template my-app ./my-app -f production-values.yamlThe rendered output can be inspected to verify that templates produce valid and expected Kubernetes manifests before an installation or upgrade is attempted.
Helm Release
A Helm release is an installed instance of a chart in a Kubernetes cluster. The same chart can be installed multiple times using different release names and configurations.
helm install frontend ./my-app
helm install backend ./my-appThese commands can create separate releases from the same chart. Each release has its own name and lifecycle.
| Concept | Meaning |
|---|---|
| Chart | Reusable package containing templates and metadata |
| Values | Configuration supplied to chart templates |
| Release | An installed instance of a chart |
| Revision | A versioned state of a release over its lifecycle |
Installing a Helm Chart
The helm install command creates a new release from a chart.
helm install my-app ./my-appA release name is followed by the chart reference. The chart can come from a local directory, packaged chart archive, repository, or another supported chart source.
helm install my-app ./my-app -n production --create-namespaceThe namespace option specifies where the release's Kubernetes resources should be created, subject to the resources and configuration defined by the chart.
Listing Helm Releases
helm list
helm list -A
helm list -n productionhelm list shows releases visible in the selected namespace. The -A option lists releases across namespaces.
Upgrading a Helm Release
When the chart or its configuration changes, helm upgrade can apply the new desired state to an existing release.
helm upgrade my-app ./my-app
helm upgrade my-app ./my-app -f production-values.yamlHelm compares the newly rendered resources with the resources associated with the release and applies the resulting changes through Kubernetes.
A common deployment workflow is to keep the chart in source control, update its templates or application image configuration, render and validate the result, and then run helm upgrade from a controlled environment such as a CI/CD pipeline.
Installing or Upgrading With helm upgrade --install
Automation often needs to handle both the initial deployment and subsequent updates. The --install option allows helm upgrade to install the release if it does not already exist.
helm upgrade --install my-app ./my-app \
-n production \
--create-namespace \
-f production-values.yamlThis pattern is particularly convenient in CI/CD pipelines because the same command can be used for both first-time deployment and later upgrades.
Helm Rollbacks
Helm keeps release history that can be used to return a release to an earlier revision when appropriate.
helm history my-app
helm rollback my-app 2The first command displays revisions associated with the release. The rollback command asks Helm to restore a previous revision.
Uninstalling a Helm Release
helm uninstall my-appThis removes the release and the Kubernetes resources managed by it according to Helm's release and resource behavior. Persistent data and resources with special retention behavior may require additional consideration.
Helm Template Functions
Helm provides many template functions that make charts more flexible. Functions can manipulate strings, format YAML, provide defaults, transform values, and perform other operations.
metadata:
name: {{ .Release.Name | quote }}The pipe syntax passes the result of one expression into another function. Functions such as quote, default, required, toYaml, nindent, and include are frequently used in charts.
resources:
{{- toYaml .Values.resources | nindent 2 }}toYaml converts a value into YAML, while nindent can format the resulting block at the required indentation level.
Helm Conditionals
Templates can conditionally include resources or configuration using if statements.
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .Release.Name }}-ingress
spec:
ingressClassName: {{ .Values.ingress.className }}
{{- end }}If ingress.enabled is false, the contents of the conditional block are not rendered. This allows one chart to support optional Kubernetes resources.
Helm with and range
Helm templates provide control structures such as with and range for working with nested configuration and lists.
env:
{{- range .Values.env }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}range iterates over a collection. This is useful for generating repeated environment variables, ports, volume mounts, hosts, or other Kubernetes configuration.
Named Templates and _helpers.tpl
Helm charts commonly use a file named _helpers.tpl to define reusable named templates. The underscore-prefixed template files are not rendered as Kubernetes manifests themselves.
{{- define "my-app.fullname" -}}
{{ .Release.Name }}-{{ .Chart.Name }}
{{- end }}The named template can then be reused from other templates.
metadata:
name: {{ include "my-app.fullname" . }}Shared helper templates are useful for generating names, standard labels, selectors, annotations, and other repeated configuration consistently.
Helm and Kubernetes Labels
Helm charts frequently generate consistent Kubernetes labels. Standard application labels can be placed in helper templates and reused by Deployments, Services, ConfigMaps, and other resources.
{{- define "my-app.labels" }}
app.kubernetes.io/name: {{ include "my-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
{{- end }}Centralizing common labels helps prevent different templates from using slightly different values for the same application.
Helm Dependencies
A chart can depend on other charts. Dependencies are useful when an application consists of several components or relies on packaged infrastructure components.
dependencies:
- name: redis
version: "20.0.0"
repository: "https://example.com/charts"The exact dependency configuration depends on the chart repository and the chart's requirements. Helm can download and manage declared dependencies using commands such as helm dependency update.
helm dependency update ./my-app
helm dependency build ./my-appSubcharts
A dependency is commonly referred to as a subchart when it is used as part of another chart. Parent charts can configure subcharts through values, subject to the dependency chart's configuration structure.
Subcharts can reduce duplication when a reusable component already exists as a maintained Helm chart. However, adding many dependencies can make a chart harder to understand and upgrade, so dependencies should be chosen deliberately.
Helm Repositories
Helm repositories provide packaged charts that can be discovered and installed using Helm.
helm repo add example https://example.com/charts
helm repo update
helm search repo exampleRepositories are useful for distributing reusable charts to teams and users. Organizations can also maintain internal chart repositories for applications and infrastructure components.
Packaging a Helm Chart
A chart can be packaged into a versioned archive for distribution.
helm package ./my-appThe resulting chart archive can be stored in a chart repository or another distribution system supported by the organization's workflow.
Helm Lint
helm lint checks a chart for potential issues and is a useful part of the development workflow.
helm lint ./my-app
helm lint ./my-app -f production-values.yamlLinting does not replace Kubernetes validation or testing, but it can catch common chart problems before deployment.
Helm Diff and Manifest Review
Before upgrading a production release, it is useful to understand which Kubernetes manifests will change. Helm itself provides rendering and release commands, while external plugins and CI tooling can provide additional diff capabilities.
helm template my-app ./my-app -f production-values.yamlRendering the manifests and reviewing them as part of a pull request or deployment pipeline makes configuration changes easier to audit.
Helm Values Schema
A chart can include values.schema.json to describe and validate the structure of values supplied to the chart. This is useful when a chart exposes many configuration options.
{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1
}
}
}A schema can help catch invalid types and unsupported configurations earlier in the deployment workflow.
Required Values
The required function can force users to provide a value rather than silently falling back to an empty or unsuitable configuration.
image:
repository: {{ required "image.repository is required" .Values.image.repository }}This can be useful for configuration that has no safe default, although defaults are generally preferable when a sensible value exists.
Helm Secrets and Sensitive Values
Helm values can contain sensitive configuration, but a normal values file should not be treated as a secure secret-management system. Kubernetes Secrets themselves also require appropriate cluster security and access controls.
When a chart creates a Kubernetes Secret, Helm can render the Secret manifest, but protecting the underlying sensitive data remains the responsibility of the deployment architecture.
Helm and Environment-specific Configuration
One of Helm's most useful features is the ability to use the same chart with different values files.
values.yaml
development.yaml
staging.yaml
production.yamlFor example, development might use one replica and a lightweight image configuration, while production uses multiple replicas, stricter resources, production ingress settings, and a specific application version.
helm upgrade --install my-app ./my-app -f development.yaml
helm upgrade --install my-app ./my-app -f staging.yaml
helm upgrade --install my-app ./my-app -f production.yamlThe chart templates remain shared while environment-specific configuration is separated into values files.
Helm and CI/CD
Helm is commonly used as part of continuous delivery pipelines. A pipeline can package or retrieve a chart, provide environment-specific values, render or validate manifests, and deploy the release to a Kubernetes cluster.
helm lint ./chart
helm template my-app ./chart -f production.yaml
helm upgrade --install my-app ./chart \
-n production \
-f production.yamlA robust pipeline should also include application tests, Kubernetes validation, security checks, and appropriate deployment verification rather than treating a successful Helm command as proof that the application is healthy.
Helm and Git
Helm charts are commonly stored in Git repositories. This allows changes to templates, values, chart metadata, and documentation to be reviewed and tracked like application code.
- Store Chart.yaml and templates in version control.
- Keep default values.yaml under version control.
- Review changes to production values carefully.
- Do not commit plaintext secrets.
- Use pull requests to review template changes.
- Version chart changes appropriately.
- Keep application and chart versioning concepts distinct.
Helm Best Practices
- Keep charts focused on one application or clearly defined component.
- Provide sensible defaults in values.yaml.
- Use clear and descriptive value names.
- Avoid exposing unnecessary internal implementation details as values.
- Use helper templates for repeated names, labels, and selectors.
- Keep selectors stable and predictable.
- Use values.schema.json when a chart has complex configuration.
- Run helm lint during development and CI.
- Render charts with helm template before deployment when practical.
- Keep environment-specific configuration in separate values files.
- Avoid committing plaintext credentials.
- Pin dependency versions when reproducibility matters.
- Document important configurable values.
- Keep chart and application versioning separate.
- Test upgrades and rollbacks rather than assuming they are equivalent to fresh installations.
Common Helm Chart Mistakes
- Putting Kubernetes manifests directly into values.yaml instead of keeping resource structure in templates.
- Using inconsistent indentation in generated YAML.
- Forgetting that Helm renders templates before Kubernetes receives the manifests.
- Creating overly complicated templates with too much business logic.
- Using hardcoded values that should be configurable.
- Exposing every possible configuration option and making the chart difficult to understand.
- Changing Deployment selectors in ways that Kubernetes does not allow.
- Using unstable labels in Service selectors.
- Assuming helm rollback automatically reverses database migrations.
- Storing production secrets in source-controlled values files.
- Failing to test charts with different values combinations.
- Ignoring dependency version changes.
- Deploying without inspecting the rendered manifests when templates are complex.
Example Helm Chart
The following simplified chart demonstrates how Chart.yaml, values.yaml, and a Deployment template work together.
apiVersion: v2
name: web-app
description: A simple web application
type: application
version: 1.0.0
appVersion: "2.0.0"replicaCount: 2
image:
repository: nginx
tag: "1.27"
service:
port: 80apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-web
labels:
app.kubernetes.io/name: web-app
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: web-app
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: web-app
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
containers:
- name: web
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.service.port }}If the chart is installed with the default values, Helm substitutes the configured replica count, image repository, image tag, release name, and service port into the template. The resulting YAML is then used to create the Kubernetes resources.
Helm Chart Development Workflow
- Create or update the chart structure.
- Define sensible defaults in values.yaml.
- Write Kubernetes resource templates.
- Move repeated configuration into helper templates.
- Add a values schema when configuration is complex.
- Run helm lint.
- Render the chart with helm template.
- Inspect the generated Kubernetes manifests.
- Validate the resulting YAML and Kubernetes resources.
- Test the chart against a development cluster.
- Upgrade an existing release to test lifecycle behavior.
- Verify rollback behavior when the chart is used in production.
- Package and distribute the chart when it is ready.
Helm vs Plain Kubernetes YAML
| Approach | Characteristics |
|---|---|
| Plain YAML | Simple and explicit Kubernetes manifests |
| Helm | Templates, configurable values, releases, upgrades, and packaging |
| Kustomize | Kubernetes-native customization through overlays and patches |
Helm is particularly useful when the same application needs configurable deployments across multiple environments or when an application should be distributed as a reusable package. Plain YAML can be easier for small applications with little configuration. Kustomize provides another approach to managing Kubernetes configuration without Helm's template system.
When Should You Use Helm?
Helm becomes especially useful when an application has multiple Kubernetes resources, requires environment-specific configuration, needs repeatable installations, or will be distributed to multiple users or clusters.
- Deploying applications with several Kubernetes resources.
- Managing development, staging, and production configurations.
- Packaging applications for other teams.
- Managing repeatable application installations.
- Versioning deployment configuration.
- Managing chart dependencies.
- Integrating Kubernetes deployments into CI/CD pipelines.
For a very small Kubernetes workload with one or two static manifests, Helm may introduce more abstraction than is necessary. The value of Helm increases as configuration, reuse, deployment lifecycle, and distribution requirements grow.
Troubleshooting Helm Charts
When a Helm deployment fails, separate template problems from Kubernetes problems. First render the chart locally and inspect the generated YAML.
helm lint ./my-app
helm template my-app ./my-app -f production.yaml
helm get manifest my-app
helm status my-app
helm history my-apphelm get manifest shows the manifests associated with a release, while helm status provides information about the release. Kubernetes commands such as kubectl describe and kubectl get events can then help investigate problems with the resulting resources.
Helm and YAML Validation
Helm adds a templating layer on top of YAML, so there are two different things to validate: the chart templates and the rendered Kubernetes manifests.
A YAML formatter can help keep values files and other YAML configuration readable. A YAML validator can catch basic syntax problems. Helm's own linting and template rendering can then expose chart-specific problems, while Kubernetes validation and cluster testing verify whether the resulting resources are appropriate for the target cluster.
Frequently Asked Questions
What is a Helm chart?
A Helm chart is a package containing Kubernetes resource templates, metadata, default values, and optionally dependencies and validation schemas. Helm uses the chart to generate and manage Kubernetes resources.
What is the difference between a Helm chart and a Helm release?
A chart is a reusable package or template definition. A release is an installed instance of that chart in a Kubernetes cluster. The same chart can be installed as multiple releases.
What is values.yaml used for in Helm?
values.yaml provides default configuration for a chart. Templates access these values through .Values, and users can override them with additional values files or command-line options.
How do I test a Helm chart without installing it?
Use helm lint to check the chart and helm template to render its Kubernetes manifests locally. The rendered output can then be inspected and validated before installation.
Can Helm deploy the same application to multiple environments?
Yes. A common approach is to use one chart with different values files for environments such as development, staging, and production.
What is Chart.yaml in Helm?
Chart.yaml contains metadata about the chart, including its name, chart version, application version, description, type, and potentially dependency information.
Can Helm roll back a deployment?
Helm can roll a release back to a previous Helm revision. However, rollback does not automatically reverse external side effects such as database migrations or changes outside the resources managed by the release.
Helpful Kubernetes and YAML Tools
Helm development often involves working with values files and generated Kubernetes YAML. Helm values formatters can help keep configuration readable, values validators can catch invalid configuration, YAML formatters can normalize YAML structure, Kubernetes YAML generators can provide manifest starting points, and YAML validators can catch syntax errors before configuration reaches a cluster.
Conclusion
Helm charts provide a reusable way to package and configure Kubernetes applications. A chart combines metadata, default values, templates, and optionally dependencies into a structure that Helm can render and install as a release.
The key concepts to understand are Chart.yaml, values.yaml, templates, releases, value overrides, chart dependencies, and the Helm rendering process. Once these concepts are clear, Helm becomes a practical way to manage repeatable Kubernetes deployments across multiple environments and clusters.
For maintainable charts, keep templates understandable, expose only useful configuration, use consistent labels and selectors, validate rendered manifests, protect sensitive values, and test both upgrades and rollbacks. Helm works best when it adds useful reuse and configuration without turning simple Kubernetes manifests into unnecessary complexity.