Helm Best Practices 2025: What Changed with Helm 4 and What You Should Know

Helm 4.0 just dropped at KubeCon — here’s everything DevOps engineers need to know about the biggest changes in 6 years.
After six years since Helm 3, the Kubernetes package manager just got its biggest update. Helm 4.0 was released at KubeCon North America 2025 (November 10–13), bringing significant architectural changes, new features, and updated best practices that every DevOps engineer needs to understand.
If you’re managing Helm charts in production, this isn’t just another minor update — it’s a fundamental shift in how Helm handles deployments. But don’t panic: the team has focused heavily on maintaining chart compatibility while modernizing the underlying architecture.
In this guide, I’ll walk you through what’s new, what’s changed, the best practices you need to adopt, and how to migrate safely.
What’s New in Helm 4.0
The Big Changes
Helm 4.0 represents the first major version bump since 2019. Here are the headline features:
1. Server-Side Apply (SSA) is Now Default
The biggest architectural change: Helm 4 ditches the three-way merge strategy in favor of Server-Side Apply, the same approach Kubernetes itself uses.
What this means:
Better conflict detection and handling
Clearer ownership of fields
More predictable upgrade behavior
Explicit errors instead of silent overwrites
2. Completely Redesigned Plugin System
The plugin architecture got a complete overhaul with support for:
CLI plugins (command extensions)
Getter plugins (custom download protocols)
Post-renderer plugins (template modifications)
WebAssembly (WASM) runtime for cross-platform plugins
3. Advanced Resource Status Monitoring
Helm now uses kstatus for intelligent resource watching:
Waits for actual readiness, not just pod creation
Better understanding of resource conditions
Smarter timeout handling
Improved debugging when things fail
4. OCI Install by Digest
Enhanced OCI registry support with digest-based installs for:
Immutable chart references
Better supply chain security
Precise version control
5. Chart v3 Support
New chart API version with:
Backwards compatibility for v2 charts
Better dependency management
Enhanced metadata support
Breaking Changes You Need to Know
1. Plugin Migration Required
All existing plugins must be updated to work with Helm 4. The HIP-0026 plugin redesign means:
# Old plugin structure (Helm 3)
my-plugin/
├── plugin.yaml
└── plugin.sh
# New plugin structure (Helm 4)
my-plugin/
├── plugin.yaml
├── main.wasm (or binary)
└── metadata.json
Action required:
Audit your plugin usage:
helm plugin listCheck with plugin maintainers for Helm 4 compatibility
Test plugins in staging before upgrading production
2. CLI Flag Renaming
Several CLI flags have been renamed for consistency:
# Helm 3
helm install --wait-for-jobs
# Helm 4
helm install --wait
Action required:
Update CI/CD scripts
Search codebase for hardcoded Helm commands
Update documentation
3. Package Restructuring (SDK Users)
If you’re using Helm as a Go library, packages have been reorganized:
// Helm 3
import "helm.sh/helm/v3/pkg/chart"
// Helm 4
import "helm.sh/helm/v4/pkg/chart/v2"
Action required:
Update import paths
Test integrations thoroughly
Review API changes in documentation
4. Server-Side Apply Conflicts
With SSA as default, conflicts are now explicit errors rather than silent overwrites:
# This will now error if another controller owns the field
helm upgrade my-app ./chart
# Use --force-conflicts to override (use carefully!)
helm upgrade my-app ./chart --force-conflicts
Important limitations:
❌ Multiple owners per manifest not supported
❌ Field ownership transfer not supported
✅ Backwards compatible with three-way merge charts (if K8s >= 1.22)
Helm 4 Best Practices: Updated for 2025
1. Embrace Server-Side Apply
Why it matters: SSA provides clearer semantics and better conflict handling.
Best Practice:
# In your chart values, be explicit about ownership
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config
annotations:
# Document who should own this resource
meta.helm.sh/owner: "my-team"
data:
config.yaml: |
setting: value
What to avoid:
Don’t rely on undocumented merge behavior
SSA is more strict about field ownership
Migration tip: Test upgrades in staging with --dry-run first to catch conflicts early.
2. Use Digest-Based OCI Installs
Why it matters: Ensures immutable deployments and better security.
Best Practice:
# Pin to specific digest, not tag
helm install my-app oci://registry.example.com/charts/my-app@sha256:abc123...
# Avoid mutable tags in production
# BAD: helm install my-app oci://registry.example.com/charts/my-app:latest
In your CI/CD:
# GitHub Actions example
- name: Install chart by digest
run: |
DIGEST=$(helm show chart oci://registry/chart:${{ github.sha }} --output json | jq -r '.digest')
helm install app oci://registry/chart@$DIGEST
3. Leverage Advanced Status Monitoring
Why it matters: Helm 4’s kstatus understands actual readiness.
Best Practice:
# Wait for real readiness, not just pod creation
helm install my-app ./chart \
--wait \
--timeout 10m
# Use specific status checks
helm install my-app ./chart \
--wait \
--wait-for-jobs \
--atomic # Rollback on failure
In your charts:
# Define readiness properly
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
4. Chart v3: Structure Your Charts Properly
Why it matters: Better organization and maintainability.
Best Practice:
my-chart/
├── Chart.yaml # Use apiVersion: v3
├── values.yaml
├── values.schema.json # JSON Schema validation
├── templates/
│ ├── _helpers.tpl # Template functions
│ ├── deployment.yaml
│ ├── service.yaml
│ └── NOTES.txt # User guidance
├── charts/ # Dependencies
└── crds/ # Custom Resource Definitions
Chart.yaml v3:
apiVersion: v3 # New in Helm 4
name: my-app
version: 1.0.0
dependencies:
- name: postgresql
version: "^12.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
5. Use Multi-Document Values Files
Why it matters: Better organization of complex configurations.
Best Practice:
# values.yaml can now contain multiple documents
---
# Global configuration
global:
domain: example.com
---
# Environment-specific overrides
env:
production:
replicas: 3
staging:
replicas: 1
Install with specific environment:
helm install my-app ./chart \
--values values.yaml \
--set env=production
6. Implement Proper Secret Management
Why it matters: Security is non-negotiable.
Best Practice — Use External Secrets Operator:
# Don't put secrets in values.yaml
# Use External Secrets Operator instead
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: app-secrets
data:
- secretKey: db-password
remoteRef:
key: /secret/data/app
property: db_password
Or use Sealed Secrets:
# Encrypt secrets before committing
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
# Include sealed-secret.yaml in your chart
What to avoid:
# NEVER do this
apiVersion: v1
kind: Secret
data:
password: cGFzc3dvcmQxMjM= # Base64 is not encryption!
7. Validate Charts Before Deployment
Why it matters: Catch errors before they hit production.
Best Practice:
# 1. Lint the chart
helm lint ./my-chart
# 2. Template and validate
helm template my-app ./my-chart \
--values values-prod.yaml \
--validate
# 3. Dry-run install
helm install my-app ./my-chart \
--values values-prod.yaml \
--dry-run \
--debug
# 4. Use external validators
helm plugin install https://github.com/instrumenta/helm-kubeval
helm kubeval ./my-chart
In your CI/CD:
# GitHub Actions example
- name: Validate Helm Chart
run: |
helm lint charts/*
helm template test charts/my-app | kubeval --strict
8. Version Control Your Chart Dependencies
Why it matters: Reproducible builds.
Best Practice:
# Chart.yaml - Pin dependency versions
dependencies:
- name: redis
version: "17.11.3" # Exact version, not range
repository: "https://charts.bitnami.com/bitnami"
Lock dependencies:
# Generate Chart.lock
helm dependency update ./my-chart
# Commit Chart.lock to version control
git add Chart.lock
git commit -m "Lock chart dependencies"
What to avoid:
# Don't use version ranges in production
dependencies:
- name: redis
version: "^17.0.0" # Could pull 17.11.x unexpectedly
9. Use Helm Test for Validation
Why it matters: Verify deployments actually work.
Best Practice:
# templates/tests/connection-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "my-app.fullname" . }}-test-connection"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "my-app.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never
Run tests:
# After installation
helm test my-app
# With verbose output
helm test my-app --logs
10. Document Your Charts Properly
Why it matters: Future you (and your team) will thank you.
Best Practice:
# Chart.yaml - Complete metadata
name: my-app
description: A production-ready application chart
type: application
version: 1.0.0
appVersion: "2.3.0"
keywords:
- web
- api
- production
home: https://github.com/myorg/my-app
sources:
- https://github.com/myorg/my-app
maintainers:
- name: Your Name
email: [email protected]
README.md template:
# My App Helm Chart
## Prerequisites
- Kubernetes 1.27+
- Helm 4.0+
## Installation
\`\`\`bash
helm install my-app ./my-app
\`\`\`
## Configuration
| Parameter | Description | Default |
|-----------|-------------|---------|
| `replicaCount` | Number of replicas | `1` |
| `image.repository` | Image repository | `myapp` |
## Examples
### Development
\`\`\`bash
helm install my-app ./my-app -f values-dev.yaml
\`\`\`
### Production
\`\`\`bash
helm install my-app ./my-app -f values-prod.yaml
\`\`\`
Migration Guide: Helm 3 to Helm 4
Step 1: Prepare Your Environment
# Install Helm 4 alongside Helm 3
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4 | bash
# Verify installation
helm version
# Check existing releases
helm list --all-namespaces
Step 2: Test Charts in Staging
# Template your charts with Helm 4
helm template my-app ./chart \
--values values-staging.yaml \
--debug
# Dry-run upgrade
helm upgrade my-app ./chart \
--values values-staging.yaml \
--dry-run \
--debug
Step 3: Check for Conflicts
# Upgrade with conflict detection
helm upgrade my-app ./chart \
--values values-staging.yaml
# If conflicts occur, inspect them
kubectl get <resource> <name> -o yaml --show-managed-fields
# Force if necessary (carefully!)
helm upgrade my-app ./chart \
--force-conflicts
Step 4: Update Plugins
# List current plugins
helm plugin list
# Check for Helm 4 compatibility
# Visit plugin repos for updates
# Update plugins
helm plugin update <plugin-name>
Step 5: Update CI/CD Pipelines
# Before (Helm 3)
- name: Deploy with Helm
run: |
helm upgrade --install my-app ./chart \
--wait-for-jobs \
--timeout 5m
# After (Helm 4)
- name: Deploy with Helm
run: |
helm upgrade --install my-app ./chart \
--wait \
--timeout 5m
Step 6: Monitor the Migration
# Check release history
helm history my-app
# Verify resources
kubectl get all -l app=my-app
# Check for SSA annotations
kubectl get deployment my-app -o yaml | grep -A 5 "managedFields"
Troubleshooting Common Issues
Issue 1: Conflict Errors After Upgrade
Symptom:
Error: UPGRADE FAILED: another controller owns this field
Solution:
# Option 1: Use --force-conflicts (understand implications first!)
helm upgrade my-app ./chart --force-conflicts
# Option 2: Identify and remove conflicting controller
kubectl get <resource> <name> -o yaml --show-managed-fields
# Option 3: Revert to three-way merge temporarily
helm upgrade my-app ./chart --three-way-merge
Issue 2: Plugin Not Working
Symptom:
Error: plugin "xyz" failed: exec format error
Solution:
# Check plugin compatibility
helm plugin list
# Update to Helm 4 compatible version
helm plugin update xyz
# Or install WASM version if available
helm plugin install https://github.com/author/plugin-wasm
Issue 3: Chart Templates Failing
Symptom:
Error: template: chart/templates/deployment.yaml: undefined variable
Solution:
# Validate with debug output
helm template my-app ./chart --debug
# Check for deprecated functions
# Some template functions may have changed
# Update to Chart API v3 if needed
# Edit Chart.yaml: apiVersion: v3
Issue 4: OCI Registry Authentication Fails
Symptom:
Error: failed to authorize: failed to fetch anonymous token
Solution:
# Login to registry
helm registry login registry.example.com \
--username your-user
# Or use credential helper
export HELM_REGISTRY_CONFIG=/path/to/config.json
# Verify
helm pull oci://registry.example.com/chart
Performance Improvements in Helm 4
Helm 4 isn’t just about features — it’s also faster:
Benchmarks (approximate):
Chart installation: ~15% faster
Template rendering: ~20% faster for complex charts
Dependency resolution: ~30% faster with content-based caching
What makes it faster:
Content-based caching for charts
Optimized dependency resolution
Parallel resource watching
Better memory management
What’s Coming Next
Helm 4’s release schedule:
Helm 4.0.0: November 2025 (KubeCon NA)
Helm 4.1.0: January 2026
Minor releases: Every 4 months
Helm 3 End of Life:
Helm 3 will reach EOL approximately 6–8 months after Helm 4 release
Estimated: July 2026
Action: Plan your migration accordingly
Conclusion
Helm 4.0 represents a significant evolution while maintaining the backwards compatibility that makes migration manageable. The shift to Server-Side Apply, redesigned plugin system, and enhanced status monitoring make Helm more robust and production-ready.
Key Takeaways:
✅ Server-Side Apply is the new default — Better conflict handling
✅ Plugin system redesigned — WASM support, better security
✅ Advanced status monitoring — True readiness detection
✅ OCI improvements — Digest-based installs for security
✅ Chart v3 support — Better dependency management
Action Items:
- Immediate:
Test your charts with Helm 4 in staging
Audit plugin usage
Update CI/CD scripts for renamed flags
2. Short-term (1–2 months):
Migrate production deployments
Update chart documentation
Train team on new features
3. Long-term (3–6 months):
Adopt SSA best practices fully
Migrate to Chart v3
Update internal tooling and scripts
Getting Started:
# Install Helm 4
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4 | bash
# Test your first chart
helm template my-app ./chart --debug
# Deploy when ready
helm upgrade --install my-app ./chart --wait
Helm 4 is production-ready and brings meaningful improvements. Start testing today, and plan your migration timeline. The Helm community has done an excellent job ensuring backwards compatibility while modernizing the tooling.
Additional Resources
Have you upgraded to Helm 4 yet? What’s your experience been? Share in the comments!




