Helm Package Manager for Kubernetes

Helm is the package manager for Kubernetes. It bundles all the Kubernetes resources for an application into a single versioned package called a chart, and provides commands to install, upgrade, roll back, and remove that package as a unit. This page covers how charts work, how to use Helm with AKS, and when to use it instead of plain kubectl.

Charts, releases, and repositories

Three concepts underpin everything in Helm:

A chart is a collection of files that describe a set of Kubernetes resources. It contains YAML templates with placeholder variables, a values.yaml file with defaults for those variables, a Chart.yaml file with metadata like name and version, and optionally a README and schema validation. Charts can be packaged as .tgz archives and shared via a repository.

A release is an instance of a chart installed in a Kubernetes cluster. If you install the same chart twice — once as staging-nginx and once as prod-nginx — you have two releases, each independent with its own configuration and upgrade history.

A repository is an HTTP server hosting packaged charts and an index file. The original stable repository was https://charts.helm.sh/stable but has been deprecated. Modern charts are hosted on Artifact Hub or on dedicated repositories maintained by each project.

Installing Helm and adding repositories

Helm is a single binary. On macOS install it with Homebrew; on Linux download it from the official release page or use the install script; on Windows use Chocolatey or the binary directly.

# macOS
brew install helm

# Linux (install script)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Verify
helm version

Add repositories before you can search for or install charts from them:

# Add the ingress-nginx chart repo
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

# Add Jetstack (for cert-manager)
helm repo add jetstack https://charts.jetstack.io

# Update your local repo cache
helm repo update

# Search for charts
helm search repo ingress-nginx
helm search hub cert-manager   # searches Artifact Hub

Installing and upgrading releases

Install a chart into your AKS cluster with helm install. The first argument is the release name; the second is the chart reference (repo/chartname or a local path).

# Create the namespace first
kubectl create namespace ingress-nginx

# Install ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --set controller.replicaCount=2 \
  --set controller.nodeSelector."kubernetes\.io/os"=linux

# Check release status
helm status ingress-nginx -n ingress-nginx

# List all installed releases across all namespaces
helm list --all-namespaces

To install cert-manager, which requires CRDs (Custom Resource Definitions) to be installed first:

# Install CRDs separately
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.crds.yaml

# Install cert-manager chart
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.14.4

When a new chart version is available or you want to change configuration, use helm upgrade:

# Upgrade to a new chart version
helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --version 4.10.0 \
  --reuse-values

# Upgrade and change a value
helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --set controller.replicaCount=3 \
  --reuse-values

—reuse-values carries forward all previously set values, so you only need to specify what changes. Without it, Helm resets to chart defaults for any value you do not explicitly provide.

Configuring charts with values.yaml

Every chart has a values.yaml file that defines the configurable parameters and their defaults. You override these by providing your own values file or using —set flags.

For production, create an environment-specific values file and commit it to source control. This makes your exact configuration reproducible and reviewable:

# prod-values.yaml
controller:
  replicaCount: 3
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 512Mi
  service:
    annotations:
      service.beta.kubernetes.io/azure-load-balancer-internal: "true"
  config:
    proxy-body-size: "50m"
    use-forwarded-headers: "true"
# Install using a values file
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  -f prod-values.yaml

# Combine a file with individual overrides
helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  -f prod-values.yaml \
  --set controller.replicaCount=4

To see what values a chart accepts before installing it:

# Show the full default values.yaml for a chart
helm show values ingress-nginx/ingress-nginx

# Show only the chart metadata
helm show chart ingress-nginx/ingress-nginx

Rollbacks and release history

Helm stores the history of every upgrade for each release. If an upgrade breaks something, you can roll back to any previous revision.

# Show the history of a release
helm history ingress-nginx -n ingress-nginx

# Output looks like:
# REVISION  STATUS     CHART                    DESCRIPTION
# 1         superseded ingress-nginx-4.9.0       Install complete
# 2         superseded ingress-nginx-4.9.0       Upgrade complete
# 3         deployed   ingress-nginx-4.10.0      Upgrade complete

# Roll back to the previous revision
helm rollback ingress-nginx -n ingress-nginx

# Roll back to a specific revision
helm rollback ingress-nginx 1 -n ingress-nginx

# Verify after rollback
helm status ingress-nginx -n ingress-nginx

Rolling back a Helm release does not automatically roll back PersistentVolumeClaims or other stateful resources that were created by the chart. Data resources require separate handling.

Note

Helm history is kept as Kubernetes Secrets. By default, Helm retains the last 10 revisions. You can change this with the —history-max flag during install or by setting HELM_MAX_HISTORY in your environment.

Helm vs plain kubectl apply

For simple single-service applications, managing a handful of YAML files with kubectl is entirely reasonable. Helm adds value when the complexity grows.

Scenariokubectl applyHelm
Single Deployment + ServiceSimple, no extra toolingOverhead not justified
App with 10+ resources across Deployments, RBAC, IngressTedious to manage atomicallySingle install/upgrade command
Deploy to multiple environments with different configDuplicate YAML files with editsOne chart, multiple values files
Rolling back a broken deploymentManual — re-apply old YAMLhelm rollback
Installing open-source software (nginx, cert-manager)Find and apply upstream YAMLhelm install from repo
Atomic install (all resources succeed or none do)No built-in atomicityAtomic with —atomic flag

Use kubectl for your own simple workloads. Use Helm when you are installing third-party software, managing applications that span many resource types, or deploying to multiple environments where configuration differs.

Uninstalling a release

helm uninstall removes all Kubernetes resources that were created by the release and deletes the release history:

# Uninstall a release
helm uninstall ingress-nginx -n ingress-nginx

# Keep history for auditing (resources still deleted)
helm uninstall ingress-nginx -n ingress-nginx --keep-history

# Dry run — show what would be deleted
helm uninstall ingress-nginx -n ingress-nginx --dry-run

Resources not created by Helm — such as PersistentVolumeClaims that were created dynamically by StatefulSets — are not deleted by helm uninstall. You must delete those manually.

Common mistakes

  1. Using —set for all configuration instead of a values file. Flags like —set controller.replicaCount=3 are not tracked anywhere. The next person who runs helm upgrade without the same flags will reset that value to the chart default. Always put environment-specific configuration in a committed values file.
  2. Installing CRD-heavy charts without reading the install notes. Some charts like cert-manager and Prometheus Operator create Custom Resource Definitions that the chart itself then tries to use. If the CRDs are not registered before the resources that depend on them, the install fails. Check the chart documentation before running helm install.
  3. Not pinning chart versions in production. Running helm upgrade myapp myrepo/myapp without a —version flag installs the latest chart version, which may include breaking changes. Always specify —version in production pipelines and test new versions in staging before rolling to production.

Frequently asked questions

What is the difference between a Helm chart and a release?

A chart is the package — a directory of templates, a values file, and metadata. A release is a specific installation of a chart in a cluster with a given set of values. You can install the same chart multiple times in different namespaces, and each installation is a separate release with its own name and history.

Does Helm store release state in the cluster?

Yes. Helm 3 stores release metadata as Kubernetes Secrets in the same namespace as the release. This means release history is available to anyone with read access to Secrets in that namespace. It also means no separate Helm server (Tiller) is needed — Helm 3 is entirely client-side.

How do I override chart values without editing values.yaml?

Use the --set flag for individual values: helm install myapp ./chart --set image.tag=2.1.0. For multiple overrides, create a separate override file and use -f: helm install myapp ./chart -f prod-values.yaml. The -f approach is better for production because the overrides are tracked in a file you can commit to source control.

Last verified: 19 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.