Part ofHelm: Kubernetes Package Management·Step 1 of 2
Kubernetes

Helm Fundamentals: Kubernetes Package Manager

Beginner60 min to complete16 min readJune 1, 2026Updated August 19, 2026

Quick answer

Helm turns multi-file Kubernetes manifests into versioned, parameterisable packages called charts. Learn to install charts from registries, override values, upgrade and roll back releases, and create your own chart.

beginner · 60 min

Before you begin

  • Kubernetes basics — Deployments, Services, Namespaces
  • kubectl configured and pointing at a cluster
  • No prior Helm experience needed
Helm
Kubernetes
Package Manager
DevOps
Charts

Helm Fundamentals: Kubernetes Package Manager

Deploying a real application to Kubernetes means writing a Deployment, a Service, a ConfigMap, maybe an Ingress and a HorizontalPodAutoscaler — all as separate YAML files. When you need to deploy the same application to dev, staging, and prod with different image tags and replica counts, you're copying files and manually editing values.

Helm solves this. A chart packages all those manifests together, replaces environment-specific values with template variables, and tracks what's deployed as a named release. Install, upgrade, and roll back with a single command.


Installing Helm

bash
1# macOS
2brew install helm
3
4# Linux (official installer)
5curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
6
7# Verify
8helm version
9# version.BuildInfo{Version:"v3.x.x", ...}

Helm 3 has no server-side component (Tiller was removed). It talks directly to the Kubernetes API using your ~/.kube/config.


Charts, Releases, and Repositories

Three concepts to internalize:

TermMeaning
ChartA package — templates + default values + metadata
ReleaseA named installation of a chart in a cluster (one chart can be installed multiple times as different releases)
RepositoryA registry of charts (like npm or apt for Kubernetes apps)

Adding Repositories

Artifact Hub is the public chart registry. Most major projects publish their charts there.

bash
1# Add the Bitnami repository (one of the most widely used)
2helm repo add bitnami https://charts.bitnami.com/bitnami
3
4# Add the ingress-nginx repository
5helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
6
7# Update the local cache (like apt update)
8helm repo update
9
10# List configured repositories
11helm repo list

Searching for charts

bash
1# Search your configured repos
2helm search repo nginx
3
4# Search Artifact Hub (requires internet)
5helm search hub nginx
6
7# See all versions of a chart
8helm search repo bitnami/nginx --versions

Installing a Chart

bash
1# Install nginx from Bitnami as a release named "my-nginx"
2helm install my-nginx bitnami/nginx
3
4# Install into a specific namespace (create it if needed)
5helm install my-nginx bitnami/nginx --namespace web --create-namespace
6
7# Install a specific chart version
8helm install my-nginx bitnami/nginx --version 18.1.0
9
10# See what would be installed without doing it
11helm install my-nginx bitnami/nginx --dry-run

After install, Helm shows a NOTES section with the chart's own instructions — usually how to get the service URL.

Listing releases

bash
helm list
helm list -n web              # In a specific namespace
helm list --all-namespaces

Checking release status

bash
helm status my-nginx
helm status my-nginx -n web

Overriding Values

Every chart has a values.yaml that defines defaults. Override them at install time.

See what's configurable

bash
# Show all default values
helm show values bitnami/nginx

# Show chart description and README
helm show readme bitnami/nginx
helm show chart bitnami/nginx

Override on the command line

bash
1# Single value
2helm install my-nginx bitnami/nginx --set replicaCount=3
3
4# Multiple values
5helm install my-nginx bitnami/nginx \
6  --set replicaCount=3 \
7  --set service.type=ClusterIP
8
9# Nested values (dot notation)
10helm install my-nginx bitnami/nginx \
11  --set resources.requests.cpu=100m \
12  --set resources.requests.memory=128Mi

Override with a values file

For more than a few values, use a file:

yaml
1# my-values.yaml
2replicaCount: 3
3
4service:
5  type: ClusterIP
6  port: 80
7
8resources:
9  requests:
10    cpu: 100m
11    memory: 128Mi
12  limits:
13    cpu: 500m
14    memory: 256Mi
bash
helm install my-nginx bitnami/nginx -f my-values.yaml

Layer multiple files (later files win):

bash
helm install my-nginx bitnami/nginx \
  -f base-values.yaml \
  -f prod-values.yaml

Upgrading a Release

bash
1# Upgrade with a new value
2helm upgrade my-nginx bitnami/nginx --set replicaCount=5
3
4# Upgrade to a specific chart version
5helm upgrade my-nginx bitnami/nginx --version 18.2.0
6
7# Upgrade, or install if not present (idempotent — use in CI)
8helm upgrade --install my-nginx bitnami/nginx -f my-values.yaml

helm upgrade --install is the standard CI/CD pattern — it works whether the release exists or not.

View upgrade history

bash
helm history my-nginx
# REVISION  STATUS      DESCRIPTION
# 1         superseded  Install complete
# 2         deployed    Upgrade complete

Rolling Back

bash
1# Roll back to the previous revision
2helm rollback my-nginx
3
4# Roll back to a specific revision
5helm rollback my-nginx 1
6
7# Dry run
8helm rollback my-nginx 1 --dry-run

Rollback is just another upgrade — it creates a new revision pointing at the old configuration.


Uninstalling

bash
helm uninstall my-nginx
helm uninstall my-nginx -n web

# Keep release history after uninstall (useful for auditing)
helm uninstall my-nginx --keep-history

Rendering Templates Without Installing

bash
# Render all templates to stdout (debugging)
helm template my-nginx bitnami/nginx -f my-values.yaml

# Render a specific template
helm template my-nginx bitnami/nginx -f my-values.yaml -s templates/deployment.yaml

helm template never connects to the cluster. Use it to inspect what would actually be applied.

Linting a chart

bash
helm lint ./my-chart

Creating Your Own Chart

bash
helm create my-app

This scaffolds:

my-app/
├── Chart.yaml           # Chart name, version, description, appVersion
├── values.yaml          # Default values
├── templates/
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── hpa.yaml
│   ├── serviceaccount.yaml
│   ├── NOTES.txt        # Post-install message
│   └── _helpers.tpl     # Named templates (reusable snippets)
└── charts/              # Bundled chart dependencies

Helm templating basics

Templates use Go's text/template package with Sprig helper functions.

yaml
1# templates/deployment.yaml
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5  name: {{ .Release.Name }}-{{ .Chart.Name }}
6  labels:
7    app: {{ .Chart.Name }}
8    release: {{ .Release.Name }}
9    version: {{ .Chart.AppVersion | quote }}
10spec:
11  replicas: {{ .Values.replicaCount }}
12  selector:
13    matchLabels:
14      app: {{ .Chart.Name }}
15  template:
16    metadata:
17      labels:
18        app: {{ .Chart.Name }}
19    spec:
20      containers:
21        - name: {{ .Chart.Name }}
22          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
23          ports:
24            - containerPort: {{ .Values.service.port }}
25          resources:
26            {{- toYaml .Values.resources | nindent 12 }}

Key built-in objects:

ObjectExampleMeaning
.Release.Namemy-appThe release name given at install
.Release.NamespaceproductionThe namespace
.Release.IsInstalltrueFirst install (vs upgrade)
.Chart.Namemy-appChart name from Chart.yaml
.Chart.Version0.1.0Chart version
.Chart.AppVersion1.5.2Application version
.Values.xxx.Values.replicaCountValue from values.yaml

Named templates in _helpers.tpl

Files starting with _ are not rendered as Kubernetes objects — they hold reusable template definitions.

yaml
# templates/_helpers.tpl
{{- define "my-app.labels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}

Use in a template:

yaml
metadata:
  labels:
    {{- include "my-app.labels" . | nindent 4 }}

Chart dependencies

Declare dependencies in Chart.yaml:

yaml
dependencies:
  - name: postgresql
    version: "13.x.x"
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled   # Only include if values.postgresql.enabled is true
bash
helm dependency update ./my-app    # Download dependencies into charts/

Install Your Chart

bash
1# From local directory
2helm install my-app ./my-app -f my-values.yaml
3
4# Package it
5helm package ./my-app
6# Produces: my-app-0.1.0.tgz
7
8# Install from package
9helm install my-app ./my-app-0.1.0.tgz

Frequently Asked Questions

Where does Helm store release state?

As Secrets in the release's namespace, not on your machine. That is why anyone with access can roll back a release from anywhere, and why an interrupted upgrade can leave a release stuck — the record exists but the operation never completed.

Why is my values override being ignored?

Almost always a path mismatch: the key does not exist at that location in the chart, so Helm accepts it and nothing consumes it. It does not warn about unknown keys. Ask Helm for the release's computed values and compare against what you intended.

How do I see what a chart will do before applying it?

Render it locally with helm template, or run the upgrade as a dry run to see what would be applied. Neither shows a diff against the live release — that needs the helm-diff plugin. Rendering first turns most template errors into a local problem rather than a partially applied release.

Why does upgrading a chart not upgrade its CRDs?

Because Helm deliberately installs CRDs on first install and never upgrades or deletes them — deleting a CRD deletes every object of that kind. Upgrade CRDs as an explicit step and read the chart's upgrade notes, which is where charts most often expect manual action.

What's Next

Official References

Next in Helm: Kubernetes Package Management

Helmfile: Managing Multiple Helm Releases

Continue

We built Podscape to simplify Kubernetes workflows like this — logs, events, and cluster state in one interface, without switching tools.

Struggling with this in production?

We help teams fix these exact issues. Our engineers have deployed these patterns across production environments at scale.