A Kubernetes deployment can fail even when an application's code is correct. A missing environment variable, an invalid YAML value, an incorrect service port, or a broken template can prevent a release from starting. In some cases, the deployment succeeds, but the application enters a crash loop because the generated configuration does not match what the application expects.
These problems become more difficult to manage when teams maintain multiple Helm charts for development, testing, staging, and production environments.
Helm helps package and deploy Kubernetes resources through reusable templates and configuration values. However, a chart that renders successfully is not necessarily valid for your cluster or safe to deploy.
This article explains how to validate Helm charts before deployment, use Helm's built-in checks, test templates, catch configuration mistakes, and integrate validation into a CI/CD pipeline.
What Is Helm Chart Validation?
Helm is a package manager for Kubernetes. A Helm chart contains templates, default values, metadata, and other files required to generate Kubernetes resource manifests.
For example, a chart might contain:
my-application/
├── Chart.yaml
├── values.yaml
├── values.schema.json
└── templates/
├── deployment.yaml
├── service.yaml
└── ingress.yaml
The values.yaml file provides default configuration. The files in templates/ generate Kubernetes manifests using those values. An optional values.schema.json file can define the structure and types of supported configuration values.
Helm chart validation checks whether the chart is correctly structured, its templates render as expected, and the resulting manifests satisfy the relevant Kubernetes requirements.
A complete validation process can include:
- Chart structure and metadata checks.
- Values schema validation.
- Template rendering.
- Kubernetes manifest validation.
- Testing against the target cluster.
- Application-specific configuration checks.
Each step catches a different class of problem. No single command guarantees that a chart will deploy and operate correctly.
Step 1: Check the Chart Structure
Start by validating the chart's basic structure.
Run the following command from the directory containing the chart:
helm lint ./my-application
The helm lint command checks a chart for common issues, including problems with chart structure, metadata, and templates.
For example, if Chart.yaml is missing required information or a template contains an obvious error, linting may identify the problem before deployment.
A basic Chart.yaml file looks like this:
apiVersion: v2
name: my-application
description: Helm chart for a sample application
type: application
version: 1.0.0
appVersion: "1.0.0"
The version field identifies the chart version. The appVersion field describes the application version and is informational; Helm does not automatically deploy that application version unless the templates use it.
Understand the Difference Between Warnings and Errors
A successful lint command is a useful starting point, but it does not prove that every configuration is correct.
Review warnings instead of ignoring them. A chart may pass linting while still producing an invalid resource for a particular set of values.
For example, the default values might render correctly, but production overrides could introduce an empty image name or an invalid port.
Validate the chart using the same configuration files and important overrides that you plan to use during deployment.
Step 2: Validate Configuration Values
Helm values control many aspects of a deployment, including container images, replicas, ports, resource limits, and environment variables.
Consider this values.yaml file:
replicaCount: 2
image:
repository: nginx
tag: "1.28"
service:
type: ClusterIP
port: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
These values describe a basic application deployment. However, Helm does not automatically know every application-specific rule.
For example, your application might require at least one replica, a non-empty image repository, or a service port within a particular range.
You can enforce such requirements with a values schema.
Add a values.schema.json File
Create a values.schema.json file in the chart directory:
{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"replicaCount",
"image",
"service"
],
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1
},
"image": {
"type": "object",
"required": [
"repository",
"tag"
],
"properties": {
"repository": {
"type": "string",
"minLength": 1
},
"tag": {
"type": "string",
"minLength": 1
}
}
},
"service": {
"type": "object",
"required": [
"port"
],
"properties": {
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535
}
}
}
}
}
The schema defines the expected types and some basic constraints for the values.
If someone supplies a string instead of an integer for replicaCount, or sets the service port to 70000, Helm can reject the configuration during validation.
The schema above intentionally covers only selected properties. In a production chart, extend it to validate the values your templates actually consume. Consider whether unknown properties should be rejected and whether every field should be required.
Important: Schema validation checks the configuration data. It does not prove that a value is operationally correct. A valid image name may refer to an image that does not exist or cannot be pulled by the cluster.
Step 3: Render Templates Before Deployment
One of the most useful Helm validation commands is helm template.
It renders chart templates into Kubernetes manifests without installing the chart into a cluster.
Run:
helm template my-release ./my-application
To use a specific configuration file:
helm template my-release ./my-application \
-f values-staging.yaml
You can also override individual values from the command line:
helm template my-release ./my-application \
--set replicaCount=3 \
--set service.port=8080
These commands help reveal the actual manifests generated by Helm.
Inspect the Rendered Deployment
Suppose your Deployment template contains:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-app
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
containers:
- name: application
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.service.port }}
After rendering the chart, verify that the output contains the expected release name, replica count, image, labels, and ports.
Look for:
- Empty or unexpected values.
- Invalid YAML indentation.
- Incorrect resource names.
- Missing labels or selectors.
- Mismatched service and container ports.
- Incorrect image references.
- Values that differ between environments.
A Deployment selector must match the labels on its pod template. If the labels differ, Kubernetes may reject the resource or the deployment may not manage the intended pods correctly.
Rendering makes these problems easier to identify before applying the manifests.
Step 4: Validate Against Kubernetes
A chart can pass linting and render successfully while producing resources that Kubernetes rejects.
For example, a template might generate an invalid field under a Deployment specification. Helm can render that YAML because template rendering does not fully validate every Kubernetes API rule.
When a suitable cluster is available, use a server-side dry run to ask the API server to validate the rendered resources without persisting them.
One approach is to pipe the rendered manifests into kubectl:
helm template my-release ./my-application \
-f values-staging.yaml |
kubectl apply --dry-run=server -f -
This requires access to a cluster that supports server-side dry-run validation, along with sufficient permissions to perform the relevant checks.
Server-side validation is useful because the API server understands the Kubernetes resource schemas and installed custom resource definitions. However, validation may still depend on cluster configuration, admission policies, and available APIs.
Understand Client-Side and Server-Side Validation
| Validation method | What it checks | Main limitation |
|---|
helm lint | Common chart and template issues | Does not validate every rendered resource against the target cluster |
helm template | Renders templates and validates Helm's rendering process | Does not install resources or fully validate them against a cluster |
| Client-side dry run | Performs available local validation | May not reflect the target cluster's current API and admission rules |
| Server-side dry run | Asks the API server to validate resources without persisting them | Requires cluster access and may not catch runtime failures |
| Actual deployment test | Tests resource creation and deployment behavior | Requires a test environment and can still miss production-specific issues |
Use more than one method when the application has important availability or security requirements.
Step 5: Catch Environment-Specific Configuration Errors
Helm charts often use different values files for development, staging, and production.
For example:
values.yaml
values-dev.yaml
values-staging.yaml
values-prod.yaml
The default configuration may work, while a production override introduces a problem.
Validate each supported configuration separately:
helm lint ./my-application \
-f values-dev.yaml
helm lint ./my-application \
-f values-staging.yaml
helm lint ./my-application \
-f values-prod.yaml
Then render each environment:
helm template my-release ./my-application \
-f values-prod.yaml \
--debug
Be careful when reviewing debug output. It may contain sensitive configuration values, so do not publish logs indiscriminately in CI systems.
Validate Values in the Same Order as Deployment
Helm supports multiple values files. Later files can override values from earlier files.
For example:
helm template my-release ./my-application \
-f values.yaml \
-f values-prod.yaml
The final rendered output reflects the merged values.
Your validation commands should use the same values files and relevant overrides as the real deployment process. Otherwise, you may validate one configuration and deploy another.
Avoid placing credentials directly in chart values committed to source control. Use an appropriate secret-management approach and ensure that validation logs do not expose sensitive data.
Step 6: Validate Charts in CI/CD
Manual checks are useful during development, but automated validation helps prevent the same errors from reaching a release.
A simple CI pipeline can run Helm linting, render the chart, and validate the resulting manifests.
For example, a shell script might look like this:
#!/usr/bin/env bash
set -euo pipefail
CHART_DIR="./my-application"
VALUES_FILE="./my-application/values-staging.yaml"
RELEASE_NAME="my-release"
echo "Checking Helm chart..."
helm lint "$CHART_DIR" -f "$VALUES_FILE"
echo "Rendering Kubernetes manifests..."
helm template "$RELEASE_NAME" "$CHART_DIR" \
-f "$VALUES_FILE" \
--debug > rendered-manifests.yaml
echo "Validating against the Kubernetes API..."
kubectl apply --dry-run=server \
-f rendered-manifests.yaml
echo "Helm validation completed."
This script assumes that Helm and kubectl are installed, the selected cluster is reachable, and the necessary permissions are available. It also assumes that the rendered chart contains resources suitable for server-side validation in that environment.
In a real pipeline, add checks for every supported deployment configuration. If the chart includes custom resources, make sure the validation cluster has the required custom resource definitions installed.
Add Policy and Security Checks
Teams with stricter requirements can add manifest validation and policy checks after rendering.
These checks can enforce rules such as:
- Containers must define resource requests and limits.
- Privileged containers are prohibited unless explicitly approved.
- Images must come from approved registries.
- Workloads must use the required security settings.
- Services must not expose unintended public access.
The exact policies depend on your organization's platform and security requirements. Keep policy checks aligned with the Kubernetes resources and controller capabilities used by your environment.
Common Helm Validation Mistakes
Validating Only the Default Values
A chart may render correctly with its default configuration but fail with production overrides.
How to fix it: Run linting and rendering for every supported environment, using the same values files as deployment.
Assuming Successful Rendering Means a Valid Deployment
helm template can produce YAML that Kubernetes rejects.
How to fix it: Add Kubernetes API validation and, where necessary, deploy to a representative test cluster.
Ignoring Service and Deployment Mismatches
A Service may target a port that the application does not listen on. Kubernetes can accept the resources even though requests fail.
How to fix it: Validate the Service selector, pod labels, target port, container configuration, and actual application listening port.
Hardcoding Environment Values
Hardcoded image names, resource settings, and hostnames can cause unexpected behavior when the chart is reused.
How to fix it: Move environment-specific settings into values files and validate the rendered result for each environment.
Exposing Secrets in Build Logs
Debug output can reveal values that should remain private.
How to fix it: Keep credentials out of committed chart values, restrict access to logs, and use appropriate secret-management tools.
Best Practices for Reliable Helm Charts
Use the following practices to make chart validation a routine part of development.
- Maintain a values schema: Define valid types, required fields, and important value constraints.
- Lint every change: Run
helm lint before merging chart updates. - Inspect rendered manifests: Review the resources generated by important values combinations.
- Validate against the target Kubernetes API: Use server-side dry runs where the environment supports them.
- Test environment overrides: Validate development, staging, and production configurations independently.
- Keep templates readable: Avoid complicated template logic when a simpler configuration is possible.
- Use representative test clusters: Include required custom resource definitions and relevant admission policies.
- Automate validation: Run checks in pull requests so that configuration errors are detected before release.
- Protect sensitive information: Avoid exposing secrets in values files, generated manifests, or CI logs.
- Test application behavior: Confirm that the deployed application starts, becomes ready, and handles requests as expected.
Advantages and Limitations of Helm Chart Validation
| Advantages | Limitations |
|---|
| Detects template and configuration errors early | Cannot guarantee that an application will work at runtime |
| Reduces failed deployments | Requires representative values and environments |
| Improves consistency across environments | Complex charts may need additional test coverage |
| Supports automated release checks | Cluster-specific validation requires access to a suitable environment |
| Helps enforce security and configuration policies | Policy rules need maintenance as requirements change |
Helm validation is most effective when used as a series of checks rather than a single command. Each stage addresses a different risk, from malformed templates to rejected Kubernetes resources and application startup failures.
Summary
Helm chart validation helps teams find Kubernetes configuration problems before they affect a deployment. Start with helm lint to catch common chart issues, use helm template to inspect generated manifests, and validate those manifests against the Kubernetes API when possible.
Test the actual values files used in each environment, add schema validation for important configuration fields, and automate the checks in CI/CD. For production workloads, combine these checks with policy validation and deployment tests.
The goal is to catch configuration mistakes while they are still easy to fix. A consistent validation process makes Helm charts easier to maintain and Kubernetes releases more predictable.
Join the conversation! Your thoughts help the community grow.