---
title: "Helm Values and Overrides: Precedence, Inspection, and Environment Patterns"
description: "How Helm values files work, the exact override precedence, inspection techniques, and patterns for managing values across environments."
url: https://agent-zone.ai/knowledge/kubernetes/helm-values-and-overrides/
section: knowledge
date: 2026-02-22
categories: ["kubernetes"]
tags: ["helm","values","configuration","overrides","oci"]
skills: ["helm-configuration","environment-management"]
tools: ["helm","kubectl"]
levels: ["intermediate"]
word_count: 861
formats:
  json: https://agent-zone.ai/knowledge/kubernetes/helm-values-and-overrides/index.json
  html: https://agent-zone.ai/knowledge/kubernetes/helm-values-and-overrides/?format=html
  api: https://api.agent-zone.ai/api/v1/knowledge/search?q=Helm+Values+and+Overrides%3A+Precedence%2C+Inspection%2C+and+Environment+Patterns
---


# Helm Values and Overrides

Every Helm chart has a `values.yaml` file that defines defaults. When you install or upgrade a release, you override those defaults through values files (`-f`) and inline flags (`--set`). Getting the precedence wrong leads to silent misconfigurations where you think you set something but the chart used a different value.

## Inspecting Chart Defaults

Before overriding anything, look at what the chart provides. `helm show values` dumps the full default `values.yaml` for any chart:

```bash
# From a repo
helm show values bitnami/postgresql

# From a local chart directory
helm show values ./my-chart

# From an OCI registry
helm show values oci://registry-1.docker.io/bitnamicharts/postgresql

# Pipe to a file for reference
helm show values bitnami/postgresql > postgresql-defaults.yaml
```

This is the single most important debugging command. When something behaves unexpectedly, compare your overrides against these defaults.

## Override Precedence

Helm merges values in a specific order. Later sources override earlier ones:

1. Chart's `values.yaml` (lowest priority)
2. Parent chart's `values.yaml` (if this is a subchart)
3. Values files passed with `-f` / `--values` (left to right)
4. Inline values with `--set`, `--set-string`, `--set-file`, `--set-json` (highest priority)

The critical rule: **rightmost wins**. If you pass multiple `-f` flags, the last file takes precedence for any conflicting keys:

```bash
# base.yaml sets replicas: 1
# production.yaml sets replicas: 3
helm upgrade --install my-app ./chart \
  -f values/base.yaml \
  -f values/production.yaml
# Result: replicas = 3 (production.yaml wins)
```

And `--set` always beats `-f`, regardless of ordering:

```bash
helm upgrade --install my-app ./chart \
  --set replicaCount=5 \
  -f values/production.yaml
# Result: replicas = 5 (--set wins over -f, always)
```

## --set vs -f: When to Use Which

Use `-f` for structured, version-controlled configuration. Use `--set` for one-off overrides, CI/CD pipeline variables, and secrets you do not want in files.

```bash
# -f for environment config (committed to git)
helm upgrade --install my-app ./chart -f values/base.yaml -f values/staging.yaml

# --set for dynamic values from CI/CD
helm upgrade --install my-app ./chart -f values/production.yaml --set image.tag="${GIT_SHA}"

# --set-string forces string type (important for numeric-looking values)
helm upgrade --install my-app ./chart --set-string podAnnotations."prometheus\.io/port"="9090"

# --set-json for complex structures inline
helm upgrade --install my-app ./chart --set-json 'resources={"limits":{"cpu":"500m","memory":"256Mi"}}'
```

Watch the escaping. Dots navigate nested keys (`ingress.hosts[0].host=example.com`). Escape literal dots with backslash (`nodeSelector."kubernetes\.io/arch"=arm64`). Avoid comma-separated `--set a=1,b=2` -- use separate `--set` flags instead.

## Dry-Run and Template Rendering

Before applying changes, render templates locally to see the actual manifests Helm will produce:

```bash
# helm template: renders locally, no cluster connection needed
helm template my-release ./chart -f values/production.yaml

# helm template with a specific template file
helm template my-release ./chart -s templates/deployment.yaml

# helm upgrade --dry-run: renders against the cluster (validates API versions, checks existing resources)
helm upgrade --install my-app ./chart \
  -f values/production.yaml \
  --dry-run
```

The difference matters. `helm template` works offline but cannot validate against your cluster's API capabilities. `--dry-run` contacts the cluster, so it catches issues like missing CRDs or unsupported API versions.

Pipe the output to search for specific values to confirm your overrides took effect:

```bash
helm template my-release ./chart -f values/production.yaml | grep -A5 "resources:"
```

## Values Schema Validation

Charts can include a `values.schema.json` file that validates values before rendering. If the schema exists, Helm rejects invalid values at install/upgrade time:

```bash
# This will fail if replicaCount must be an integer and you pass a string
helm upgrade --install my-app ./chart --set replicaCount=abc
# Error: values don't meet the specifications of the schema
```

When writing your own charts, add a `values.schema.json` to catch misconfigurations early. Even a minimal schema that enforces required fields and types saves debugging time.

## Environment-Specific Values Pattern

The most common pattern is a layered file structure with base defaults and per-environment overrides:

```
my-chart/
  values/
    base.yaml          # shared defaults
    dev.yaml            # dev overrides (low resources, debug logging)
    staging.yaml        # staging (moderate resources, staging URLs)
    production.yaml     # production (high resources, real URLs, replicas)
```

```bash
# Dev deployment
helm upgrade --install my-app ./chart -f values/base.yaml -f values/dev.yaml

# Production deployment
helm upgrade --install my-app ./chart -f values/base.yaml -f values/production.yaml
```

Keep `base.yaml` as the source of truth for structure, and environment files as minimal diffs. Do not duplicate the entire values file per environment -- only override what changes.

## Helm OCI Registry Support

Helm 3.8+ supports OCI registries as chart repositories. This replaces the older `helm repo add` workflow:

```bash
# Pull a chart from an OCI registry
helm pull oci://registry-1.docker.io/bitnamicharts/postgresql --version 16.4.1

# Install directly from OCI
helm upgrade --install my-pg oci://registry-1.docker.io/bitnamicharts/postgresql \
  --version 16.4.1 \
  -f values/postgresql.yaml

# Push your own chart to an OCI registry
helm package ./my-chart
helm push my-chart-1.0.0.tgz oci://ghcr.io/myorg/charts

# Login to a private OCI registry
helm registry login ghcr.io -u USERNAME -p TOKEN
```

OCI charts do not need `helm repo update`. Each pull fetches the exact version. This makes builds more reproducible and eliminates stale repo index issues.

## Debugging Values Problems

When a deployment does not behave as expected:

```bash
# See what values were explicitly set for a release
helm get values my-release -n my-namespace

# See everything, including chart defaults
helm get values my-release -n my-namespace --all

# See the rendered manifests that were applied
helm get manifest my-release -n my-namespace

# Diff between two revisions (requires helm-diff plugin)
helm diff revision my-release 3 4
```

Compare the output of `helm get values --all` against `helm show values <chart>` to spot unintended defaults overriding your configuration.

