You learned that values.yaml contains default configuration and environment-specific files override those defaults. That was enough to deploy basic agents across environments.
But production deployments require more: clarity about which override takes precedence when multiple are specified, validation that required fields are present before rendering, and organizational patterns that keep complex values readable as your chart grows. This lesson teaches the complete values architecture that production charts depend on.
This lesson covers 8 concepts in 4 groups:
Prerequisites: You should be comfortable with:
Time estimate: 45-60 minutes
When you deploy a Helm chart, values come from multiple sources. Understanding the order matters—if you override something and it doesn't work, you're probably at the wrong level of the hierarchy.
Here's what happens in order, with later sources overriding earlier ones:
Level 1: Chart Defaults (values.yaml)
This is the baseline. Every configuration option your chart supports should have a sensible default here:
Output: This values.yaml is used when you run helm install task-api ./task-api-chart with no overrides.
When Helm renders templates, it replaces {{ .Values.replicaCount }} with 3, {{ .Values.image.tag }} with v1.0.0, etc.
Level 2: Environment-Specific Files (-f values-prod.yaml)
When deploying to production, you don't modify values.yaml (it's version-controlled and shared). Instead, you create environment-specific files that override only the values that differ:
Output: When you run:
Helm merges these two YAML files. The result:
Key principle: Only specify values you're changing in environment files. Keep defaults in values.yaml.
Level 3: Command-Line --set Overrides
For one-off changes (emergency fixes, testing), you can override values directly via CLI:
This runs at the highest priority. The effective values would have:
Output: Same structure as before, but with CLI overrides applied last.
Let's verify the precedence with a real example:
Output (Test 1: Defaults):
Output (Test 2: With -f values-prod.yaml):
Output (Test 3: With -f + --set replicas=10):
The pattern is clear: --set beats -f, which beats values.yaml defaults.
You've learned how Helm merges values from multiple sources. Quick reference:
Self-check:
If you run helm install my-app ./chart -f values-prod.yaml --set replicas=7, and values-prod.yaml has replicas: 5, what's the final replica count?
Answer7 (--set has highest priority)
Which values source should contain passwords and API keys?
AnswerNone—use Kubernetes Secrets or --set with external secret managers
When would you use --set instead of creating a new environment file?
AnswerEmergency hotfixes, testing new values, or one-off debugging (not for permanent config)
Common mistakes:
As your chart grows, values.yaml can become unwieldy. Should you organize values hierarchically or keep them flat? The answer depends on cognitive load and reusability.
Advantages:
Disadvantages:
Advantages:
Clear organization (all agent settings grouped, all database settings grouped)
Template access is intuitive: {{ .Values.agent.replicas }}
Environment overrides are cleaner:
Level: WARN
Not like this (organized by location in template):
The first approach is maintainable. The second scatters related values across different top-level keys.
You've learned how to structure values.yaml for maintainability. Quick reference:
Self-check:
Which structure is better for a chart with agent, database, redis, and monitoring configuration?
AnswerNested—group by concept (agent., database., redis., monitoring.)
How do you access agent.config.logLevel in a template?
Answer {{ .Values.agent.config.logLevel }}
What's wrong with organizing values by template file (deployment., service., configMap.*)?
AnswerScatters related configuration—database password separated from database host just because they're in different templates
Common mistakes:
Production deployments typically use three environments: development (for testing), staging (for pre-production), and production. Each has different configurations—resource limits, replica counts, security settings, and external dependencies.
File 1: values.yaml (Development Defaults)
This is the baseline—what most developers use locally. Minimal resources, one replica, verbose logging:
Output: When you run helm install task-api ./task-api-chart, you get:
File 2: values-staging.yaml
Staging mirrors production more closely—multiple replicas, tighter resources, and real external services:
Output: When you run helm install task-api ./task-api-chart -f values-staging.yaml, you get:
File 3: values-prod.yaml
Production maximizes availability and performance:
Output: When you run helm install task-api ./task-api-chart -f values-prod.yaml, you get:
Each command uses the same chart with different configurations. The chart stays in source control, environment files stay in source control, and Helm handles the merging.
You've learned the three-tier environment pattern. Quick reference:
Self-check:
Should values-prod.yaml repeat all values from values.yaml?
AnswerNo—only override what differs from defaults (replicas, resources, logging, external services)
Where should production database passwords be stored?
AnswerKubernetes Secrets, referenced in templates via secretKeyRef or --set at deploy time
What's the advantage of the three-tier pattern over a single values.yaml?
AnswerSame chart deploys to all environments with appropriate config; changes tracked in version control; minimal duplication
Common mistakes:
While environment files are preferred (they're version-controlled and documented), --set overrides are useful for debugging, quick tests, and emergency patches. Understanding the syntax is essential.
Each --set takes the path to the value (using dot notation) and the new value. The chart is installed with those overrides applied.
Output: The effective values have:
By default, --set tries to infer the type (number vs string). For values that look like numbers but should be strings, use --set-string:
Why it matters: If your template stores {{ .Values.agent.apiKey }} in an environment variable, it needs to be a string, not a number.
When you have multi-line values (TLS certificates, JSON configs), loading from a file is cleaner:
The file's contents become the value of agent.customConfig. In your template, you can access it as:
Output: The environment variable contains the entire JSON config from the file.
You've learned three --set variants for different value types. Quick reference:
Self-check:
When would --set agent.port=8000 fail but --set-string agent.port=8000 succeed?
AnswerWhen template expects string but --set infers number (environment variables need strings)
Why use --set-file instead of --set for TLS certificates?
AnswerCertificates are multi-line and contain special characters; loading from file avoids escaping issues
Should you use --set for permanent configuration changes?
AnswerNo—use environment files (version-controlled, documented). Use --set for temporary/emergency changes only
Common mistakes:
As your chart grows, it's easy to make mistakes: typos in value names, wrong types (string vs number), missing required fields. The chart installs but doesn't work as expected, leading to debugging nightmares.
values.schema.json is a JSON Schema file that validates values before rendering. Helm refuses to render if required fields are missing or types don't match.
Place this in task-api-chart/values.schema.json.
Now when you run helm with invalid values, it catches the error:
As your chart grows, accessing deeply nested values in templates becomes essential. Understanding the dot notation and when to use bracket notation saves time.
This is readable and works for most cases. The template engine navigates the YAML structure using dots.
When iterating over values, use the correct scope:
In your template:
Output:
When accessing nested values repeatedly, with simplifies templates:
Instead of:
The with block sets . to the nested object, reducing repetition.
Output: Same result, but cleaner template code.
Template access patterns:
Self-check:
What happens if you deploy with --set agent.logLevel=TRACE when schema only allows DEBUG/INFO/WARN/ERROR?
AnswerHelm rejects with validation error: "Unsupported value" (prevents invalid deployment)
When should you use with instead of repeated dot notation?
AnswerWhen accessing multiple fields from the same nested object (cleaner, less repetition)
What's the benefit of schema validation over template-based checks?
AnswerFails fast before rendering (better error messages), validates types/formats (catches typos), documents valid options
Common mistakes:
Every value should have a default that allows the chart to deploy and function, even if suboptimally:
Not like this (missing defaults):
Use YAML comments in values.yaml to explain what each value does and valid options:
Output: Developers know what each value does, valid options, and environment-specific recommendations without reading the chart code.
Group values by concept and function:
Never put passwords, API keys, or tokens in values.yaml. These should come from Kubernetes Secrets or external secret management:
Instead:
Or use --set with Secret values at deploy time:
Before moving to exercises, review these frequent errors when working with Helm values:
Quick validation checklist before deploying:
Create a values.yaml for an AI agent chart with:
Solution:
Create values-staging.yaml and values-prod.yaml that override the development defaults:
Staging Requirements:
Production Requirements:
Solution:
Create a Helm chart and verify that values override in the correct order.
Steps:
Output:
Verify that:
Create a JSON Schema that validates:
Solution:
Save as task-api-chart/values.schema.json.
Test that Helm rejects invalid values according to schema:
Now it's time to use your understanding of values hierarchy and override precedence to refine a real deployment scenario.
You're deploying your AI agent to three environments, but the current values setup has issues:
Ask AI: "Help me redesign our Helm chart values files. We're deploying an AI agent to dev, staging, and production. Create a values.yaml with sensible defaults, values-staging.yaml and values-prod.yaml that only override what differs, and values.schema.json that validates the required fields. Include comments documenting each value."
Review the AI's suggestions:
Tell AI: "I missed something in my requirements. The agent needs to support custom API endpoints for different providers (OpenAI, Anthropic, Ollama). Add that to the values structure and schema. Also, the staging environment should use the same replicas as production (for realistic load testing), so only the database connection differs."
Ask AI: "Walk me through the precedence hierarchy. If I run: helm install task-api ./task-api-chart -f values-prod.yaml --set agent.replicas=3, what will the final replica count be? Why?"
AI's answer should explain that --set has highest priority, so replicas will be 3 (not 5 from values-prod.yaml).
Compare your final values structure to your learning objectives:
If all are "yes," you're ready for Lesson 5 (Chart Dependencies). If any are "no," ask AI to clarify that specific concept.
You built a helm-chart skill in Lesson 0. Test and improve it based on what you learned.
Ask yourself:
If you found gaps: