Kubernetes
Helm
Docker
DevOps
CI/CD

Helm Set Docker Image Tag Dynamically

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

The normal way to set a Docker image tag dynamically in Helm is to make the tag a chart value and override it at deploy time. That keeps the chart reusable while letting CI, release tooling, or an operator choose the exact image version for each deployment.

Define the Tag in values.yaml

Start by modeling the image as structured values rather than hardcoding the full image string in the template.

yaml
1image:
2  repository: ghcr.io/example/my-app
3  tag: "latest"
4  pullPolicy: IfNotPresent

Then reference those values in the workload template.

yaml
1containers:
2  - name: my-app
3    image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
4    imagePullPolicy: {{ .Values.image.pullPolicy }}

This is the core pattern. Once the template is wired that way, the tag can be changed without editing the chart source.

Override the Tag from the CLI

The most common dynamic override is --set during helm upgrade --install.

bash
1TAG=1.4.7
2
3helm upgrade --install my-app ./chart \
4  --set image.tag="$TAG"

In CI, TAG is often:

  • a Git commit SHA
  • a semantic version
  • a build number
  • an environment-specific promoted tag

That makes the chart static while the release artifact stays dynamic.

Prefer --set-string for Tags

Some tags look numeric or contain characters that Helm and YAML may interpret in surprising ways. To avoid type conversion problems, prefer --set-string for tags.

bash
helm upgrade --install my-app ./chart \
  --set-string image.tag="2026.03.07-rc1"

This is especially helpful when tags contain dots, leading zeros, or long commit-like values.

Environment-Specific Values Files

If the tag should vary by environment but not necessarily by each deploy command, use values files.

values-prod.yaml:

yaml
image:
  repository: ghcr.io/example/my-app
  tag: "1.4.7"

Deploy with:

bash
helm upgrade --install my-app ./chart -f values-prod.yaml

This is still dynamic, just at the file level rather than the CLI flag level.

For pipelines, a common pattern is:

  • base chart values in values.yaml
  • environment defaults in values-prod.yaml
  • final release tag injected through --set-string

Use Commit SHAs or Immutable Tags

From an operational perspective, dynamic does not mean arbitrary. You should still prefer immutable image tags over mutable tags such as latest.

Good example:

bash
helm upgrade --install my-app ./chart \
  --set-string image.tag="sha-7d9f1c2"

That makes rollbacks and incident analysis much easier because the running image version is unambiguous.

Keep the Chart, Build, and Registry Aligned

Dynamic tagging only works if the image really exists in the registry before Helm tries to deploy it.

A typical CI order is:

  1. build image
  2. push image
  3. deploy chart with that exact tag

If the deployment step runs first, Kubernetes may accept the manifest but fail to pull the image later.

Avoid Hardcoding the Full Image String Repeatedly

Bad pattern:

yaml
image: "ghcr.io/example/my-app:1.4.7"

If that string is embedded in multiple templates, every tag change becomes a chart edit. Keep repository and tag separate so the deployment tool can override only the changing part.

You can also centralize image rendering in a helper template if the chart is large, but do that only when reuse justifies the added indirection.

Debugging Deployed Values

If the wrong image tag is running, inspect the rendered manifest and the release values.

bash
helm get values my-app
helm get manifest my-app

That tells you whether the problem is:

  • the values override was wrong
  • the template rendered incorrectly
  • the cluster is running an old release

Debugging the rendered output is faster than guessing based on the chart source alone.

Common Pitfalls

  • Hardcoding the image tag directly in templates.
  • Using latest and then losing traceability during rollbacks.
  • Forgetting that tags can be parsed oddly and not using --set-string.
  • Deploying a tag before the image is pushed to the registry.
  • Spreading image-tag logic across multiple templates instead of one consistent values model.

Summary

  • Put the image tag in Helm values, not directly in template literals.
  • Override the tag dynamically with --set-string or environment-specific values files.
  • Prefer immutable tags such as commit SHAs or release versions.
  • Ensure the image is published before deploying the chart that references it.
  • Debug dynamic tag issues by inspecting release values and rendered manifests.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.