DevOps

Build a Helm chart from zero (without `helm create`)

Every file in a Helm chart, explained. Deploy your first real chart in 30 minutes without copy-pasting a boilerplate.

helm create myapp generates 15 files you don’t understand and never touch. This guide builds a Helm chart from ONE file up so you actually know what each piece does.

What Helm actually is

Helm = the package manager for Kubernetes. It bundles your K8s YAMLs into a reusable “chart” with configurable values.

Without Helm: 10 YAML files, hard-coded values, painful to reuse. With Helm: 1 chart, values.yaml, install with helm install.

The minimum viable Helm chart (4 files)

myapp/
├── Chart.yaml              ← identity of the chart
├── values.yaml             ← default configurable values
└── templates/
    ├── deployment.yaml     ← K8s Deployment with {{ placeholders }}
    └── service.yaml        ← K8s Service with {{ placeholders }}

That’s it. Four files. A real Helm chart.

Here’s what the actual folder looks like after running helm create, along with the Chart.yaml metadata Helm auto-generates:

File 1 — Chart.yaml

apiVersion: v2
name: myapp
description: My first Helm chart
type: application
version: 0.1.0          # chart version
appVersion: "1.0.0"     # your app's version

Helm reads this to know what your chart is called + what version.

File 2 — values.yaml

image:
  repository: nginx
  tag: latest
  pullPolicy: IfNotPresent

replicaCount: 2

service:
  type: ClusterIP
  port: 80

These are the DEFAULTS. Users of your chart override them via --set or their own values file.

File 3 — templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}

Notice {{ .Values.replicaCount }} — that’s a Go template placeholder. At install time, Helm replaces it with the value from values.yaml.

Special values Helm gives you:

  • .Release.Name — the name you chose when installing (helm install my-app ...)
  • .Chart.Name — from Chart.yaml (myapp)
  • .Values.xxx — anything from values.yaml

File 4 — templates/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}
spec:
  type: {{ .Values.service.type }}
  ports:
  - port: {{ .Values.service.port }}
    targetPort: 80
  selector:
    app: {{ .Release.Name }}

Install your chart

From the folder containing myapp/:

helm install my-app ./myapp

Verify:

kubectl get deployments,services

You’ll see my-app created:

Override values at install time

helm install my-app ./myapp --set replicaCount=5 --set image.tag=1.25

Or use a custom values file:

helm install my-app ./myapp -f custom-values.yaml

Upgrade the release

Change values in values.yaml → run:

helm upgrade my-app ./myapp

Helm diffs the current release vs new manifests, applies changes.

Rollback if things break

helm history my-app         # see revisions
helm rollback my-app 2      # revert to revision 2

Helm keeps every deploy as a K8s Secret. You can roll back weeks later.

The full “real” Helm chart adds

  • templates/_helpers.tpl — reusable template helpers (naming, labels)
  • templates/ingress.yaml — Ingress if needed
  • templates/serviceaccount.yaml — ServiceAccount
  • templates/hpa.yaml — auto-scaling
  • .helmignore — files to exclude from chart package

But start with the 4 files above. Add complexity when you actually need it.

Publishing your chart

Turn your myapp/ folder into a .tgz:

helm package myapp

Upload to a chart repo (GitHub Pages works free, or ChartMuseum).

Users install:

helm repo add myrepo https://your-github-pages.com
helm install my-app myrepo/myapp

Why Helm actually helps

  • Reuse: same chart deployed 10 times with different values
  • Version control: upgrade + rollback with one command
  • Distribution: share your chart, others install with 2 commands
  • Templating: loops, conditionals, helpers for complex apps

Common mistakes

  • Committing values.yaml with secrets — never. Use --set or external secrets
  • Not versioning your chart — bump version in Chart.yaml on every change
  • Overusing templates — if you have zero conditionals, plain YAML works fine

Helm becomes worth it when you deploy the same app to 3+ environments or share your app with others.

Recommended

DevOps YAML Pack

36 production-ready configs — Kubernetes, Docker Compose, GitHub Actions, Terraform, Helm, Ansible. Every file heavily commented. Copy, paste, ship.

Get the pack — ₹499 →
Never miss an article