Overview
Relevant Files
README.mdAGENTS.mdgo.modcmd/helm/helm.gopkg/action/pkg/chart/pkg/engine/pkg/storage/
Helm is a package manager for Kubernetes written in Go. It streamlines installing and managing Kubernetes applications by rendering templates and communicating with the Kubernetes API. Think of it like apt/yum/homebrew for Kubernetes.
What Helm Does
Helm packages pre-configured Kubernetes resources into Charts—reusable, versioned packages containing:
- A
Chart.yamlmetadata file describing the package - One or more templates with Kubernetes manifest files
- Optional dependencies and configuration files
Charts can be stored locally or fetched from remote repositories, making it easy to share and deploy applications consistently across environments.
Project Status
The repository maintains two active development branches:
mainbranch: Helm v4 (unstable, under active development)dev-v3branch: Helm v3 (stable, current production version)
Changes are made to main first, then backported to dev-v3 to ensure all improvements reach the stable release.
Architecture Overview
Loading diagram...
Core Components
Command Layer (pkg/cmd/): Cobra-based CLI interface handling user input and routing to appropriate actions.
Action Layer (pkg/action/): Core operations including install, upgrade, rollback, uninstall, and release management. All actions share a common Configuration object.
Chart Engine (pkg/engine/): Template rendering using Go templates with Sprig functions for advanced templating capabilities.
Storage Layer (pkg/storage/): Pluggable backends for storing release metadata—supports Kubernetes Secrets, ConfigMaps, and SQL databases.
Kubernetes Integration (pkg/kube/): Abstracts Kubernetes client interactions, resource management, and status tracking.
Registry Support (pkg/registry/): OCI-compliant chart repository support for modern chart distribution.
Key Design Patterns
- Shared Configuration: All actions use a common
Configurationobject for consistent state management - Dual Chart Support: Stable v2 charts in
/pkg/chart/, next-gen v3 charts in/internal/chart/v3/ - Pluggable Storage: Release storage abstraction allows different backends without changing core logic
- Plugin System: Extensible architecture supporting custom plugins via subprocess or Extism runtimes
Architecture & Data Flow
Relevant Files
pkg/action/action.go- Configuration and shared dependenciespkg/cmd/root.go- CLI entry point and command setuppkg/chart/interfaces.go- Chart abstraction layerpkg/engine/engine.go- Template rendering enginepkg/storage/storage.go- Release storage abstractionpkg/release/interfaces.go- Release data structures
High-Level Architecture
Helm follows a layered architecture with clear separation of concerns:
- CLI Layer (
pkg/cmd/) - Cobra-based command handlers that parse user input and delegate to actions - Action Layer (
pkg/action/) - Core business logic for operations (install, upgrade, rollback, etc.) - Chart Layer (
pkg/chart/) - Chart loading, parsing, and dependency resolution - Rendering Layer (
pkg/engine/) - Go template rendering with Sprig functions - Storage Layer (
pkg/storage/) - Pluggable release persistence backends - Kubernetes Layer (
pkg/kube/) - Kubernetes API interaction
Data Flow: Install Operation
Loading diagram...
Configuration & Dependency Injection
The Configuration struct in pkg/action/action.go serves as the central dependency container:
- RESTClientGetter - Loads Kubernetes clients from kubeconfig
- Releases - Storage interface for persisting release metadata
- KubeClient - Kubernetes API client for resource operations
- RegistryClient - OCI registry client for chart distribution
- Capabilities - Kubernetes cluster capabilities (API versions, resources)
- CustomTemplateFuncs - User-defined template functions
All action types (Install, Upgrade, Rollback, etc.) embed this configuration, ensuring consistent access to shared dependencies.
Template Rendering Pipeline
The Engine in pkg/engine/engine.go processes charts through these stages:
- Chart Traversal - Recursively processes chart and subchart templates
- Value Scoping - Isolates values per chart to prevent cross-chart pollution
- Template Compilation - Compiles Go templates with Sprig functions
- Rendering - Executes templates with merged values
- Output Mapping - Returns
map[string]stringof filename to rendered content
Storage Abstraction
The Storage struct wraps pluggable drivers supporting multiple backends:
- ConfigMap Driver - Stores releases as Kubernetes ConfigMaps
- Secret Driver - Stores releases as Kubernetes Secrets
- Memory Driver - In-memory storage for testing
- SQL Driver - Relational database backend
Each driver implements the Driver interface with Create, Get, Update, Delete, and List operations. The Storage layer adds release history management and MaxHistory enforcement.
Release Lifecycle
Releases flow through these states:
- Pending - Initial state during install/upgrade
- Deployed - Successfully applied to cluster
- Superseded - Replaced by newer release version
- Failed - Operation failed, release rolled back
- Uninstalling - Marked for deletion
- Uninstalled - Deleted from cluster
Each release version is immutable once stored, enabling safe rollback operations.
CLI & Commands
Relevant Files
pkg/cmd/root.gopkg/cmd/install.gopkg/cmd/upgrade.gopkg/cmd/uninstall.gopkg/cmd/list.gopkg/cmd/get.gopkg/action/cmd/helm/helm.go
Architecture Overview
Helm's CLI is built on Cobra, a Go framework for building command-line applications. The architecture separates concerns into two layers:
- Command Layer (
pkg/cmd/): Handles CLI parsing, flags, and user interaction - Action Layer (
pkg/action/): Contains the business logic for each operation
This separation allows the action layer to be used programmatically without the CLI.
Loading diagram...
Command Structure
The root command is initialized in cmd/helm/helm.go and creates a Configuration object that is shared across all actions. Commands are organized into two categories:
Release Commands (manage deployed releases):
install– Deploy a chart to create a new releaseupgrade– Update an existing release to a new chart versionuninstall– Remove a release and its resourceslist– Display all releases in a namespaceget– Retrieve detailed information about a release (with subcommands:all,values,manifest,hooks,notes,metadata)rollback– Revert to a previous release versionstatus– Show the status of a named releasehistory– Display release version history
Chart Commands (manage chart repositories and definitions):
repo– Manage chart repositories (add, remove, list, update, index)search– Search for charts in repositoriespull– Download a chart from a repositoryshow– Display chart information (values, README, CRDs)create– Generate a new chart scaffolddependency– Manage chart dependencieslint– Validate chart syntaxpackage– Bundle a chart into a versioned archiveverify– Verify chart provenance and integrity
Core Action Classes
Each command delegates to an action class in pkg/action/:
- Install: Deploys a chart, creates release objects, applies Kubernetes manifests
- Upgrade: Updates existing releases, handles install-or-upgrade logic
- Uninstall: Removes releases, optionally preserves history
- List: Queries releases with filtering by status, namespace, and custom patterns
- Get: Retrieves release metadata, manifests, values, and hooks
All actions share a Configuration object that provides:
- Kubernetes client access
- Release storage backend (Secrets, ConfigMaps, or SQL)
- Registry client for OCI chart support
- Template rendering engine
- Logging and capability detection
Flags and Options
Commands support common flags for:
- Namespace selection:
--namespace,--all-namespaces - Output formatting:
--output(table, json, yaml) - Dry-run modes:
--dry-run(client-side or server-side) - Value overrides:
--values,--set,--set-string - Chart sources:
--repo,--version,--devel - Kubernetes interaction:
--kubeconfig,--context,--timeout
Flags are registered using Cobra's flag API and bound to action struct fields for easy access during execution.
Plugin System
Helm supports client-side plugins via the plugin command:
plugin install– Install a plugin from a path or URLplugin list– Show installed pluginsplugin uninstall– Remove a pluginplugin update– Update a plugin
Plugins are discovered and executed as external binaries, allowing users to extend Helm's functionality without modifying core code.
Chart Loading & Processing
Relevant Files
pkg/chart/loader/load.go- Main chart loading dispatcherpkg/chart/v2/loader/load.go- v1/v2 chart loader implementationinternal/chart/v3/loader/load.go- v3 chart loader implementationpkg/chart/loader/archive/archive.go- Archive extraction and securitypkg/downloader/manager.go- Dependency resolution and downloadinternal/resolver/resolver.go- Semantic version resolutionpkg/chart/v2/chart.go- Chart data structuresinternal/chart/v3/chart.go- v3 Chart data structures
Helm charts are loaded through a unified dispatcher that automatically detects the chart format (v1, v2, or v3) and routes to the appropriate loader. The loading process handles both directory-based charts and compressed .tgz archives, with built-in security checks and support for chart dependencies.
Loading Flow
The entry point is pkg/chart/loader/load.go, which provides a format-agnostic Load() function. This function:
- Detects whether the input is a directory or file
- Reads
Chart.yamlto determine the API version - Routes to the appropriate version-specific loader (
v2loadorv3load)
// Detects chart version from Chart.yaml and routes accordingly
func LoadDir(dir string) (chart.Charter, error) {
data, err := os.ReadFile(filepath.Join(dir, "Chart.yaml"))
c := new(chartBase)
yaml.Unmarshal(data, c)
switch c.APIVersion {
case c2.APIVersionV1, c2.APIVersionV2, "":
return c2load.Load(dir)
case c3.APIVersionV3:
return c3load.Load(dir)
}
}
Chart Structure
Both v2 and v3 charts share a common structure defined in their respective chart.go files:
- Metadata - Chart.yaml contents (name, version, dependencies, etc.)
- Templates - Kubernetes manifest templates in
templates/directory - Values - Default configuration from
values.yaml - Schema - Optional JSON schema for value validation
- Files - Miscellaneous files (README, LICENSE, etc.)
- Raw - Original file contents (used for
helm show values) - Lock - Dependency lock information from
Chart.lock - Dependencies - Loaded subchart references
Archive Processing
Charts distributed as .tgz files are extracted via pkg/chart/loader/archive/archive.go with strict security controls:
- Size limits - Max 100 MiB decompressed, 5 MiB per file
- Path validation - Prevents directory traversal attacks
- UTF-8 BOM handling - Strips byte order marks from text files
- Tar extraction - Safely unpacks gzip-compressed tar archives
The LoadArchiveFiles() function reads the archive into memory as BufferedFile objects before processing, ensuring all security checks pass before any files are written.
Dependency Resolution
The pkg/downloader/manager.go handles chart dependencies through a multi-step process:
- Load - Read the chart directory and extract dependencies from metadata
- Resolve - Use semantic version constraints to find exact versions
- Download - Fetch resolved charts from repositories
- Lock - Write
Chart.lockwith resolved versions and digest
// Manager.Update() orchestrates the full dependency workflow
func (m *Manager) Update() error {
c, err := m.loadChartDir()
req := c.Metadata.Dependencies
repoNames, err := m.resolveRepoNames(req)
lock, err := m.resolve(req, repoNames)
err = m.downloadAll(lock.Dependencies)
return writeLock(m.ChartPath, lock, ...)
}
Version Resolution
The internal/resolver/resolver.go package resolves semantic version constraints to specific versions:
- Local charts - Resolved from
charts/subdirectories - File URLs - Resolved from
file://paths on disk - Repository charts - Resolved from configured Helm repositories
- Registry charts - Resolved from OCI registries
The resolver uses github.com/Masterminds/semver/v3 to evaluate version constraints and selects the best matching version from available options.
Format Differences
v1/v2 Charts (in pkg/chart/v2/):
- Support deprecated
requirements.yamlandrequirements.lock - Default to APIVersion v1 if unspecified
- Maintain backward compatibility with Helm 2
v3 Charts (in internal/chart/v3/):
- Require explicit
apiVersion: v3 - Use only
Chart.yamlandChart.lock - Default to v3 if APIVersion is missing
- Support library charts via
type: library
Both versions support the same core features: templates, values, schemas, and dependencies. The main difference is metadata organization and deprecation handling.
Template Rendering Engine
Relevant Files
pkg/engine/engine.go- Core rendering engine and orchestrationpkg/engine/funcs.go- Template function registration and Sprig integrationpkg/engine/files.go- File access and manipulation in templatespkg/engine/lookup_func.go- Kubernetes cluster lookups from templates
Helm's template rendering engine transforms chart templates into Kubernetes manifests using Go's text/template package enhanced with Sprig functions and custom Helm-specific capabilities.
Architecture Overview
Loading diagram...
Core Rendering Flow
The Engine struct in pkg/engine/engine.go orchestrates rendering through these stages:
- Template Collection -
allTemplates()recursively gathers templates from the chart and all dependencies, applying value scoping so each chart only sees its own values - Template Parsing - Templates are parsed in predictable order (shallow paths first) to enable template sharing and includes
- Function Registration - Sprig functions are loaded, custom functions added, and late-bound functions (
include,tpl,lookup) are injected - Execution - Each non-partial template is executed with its scoped values, producing rendered manifests
- Output Mapping - Results returned as
map[string]stringwhere keys are template paths and values are rendered content
Template Functions
The engine provides three categories of functions:
Sprig Functions - 100+ utility functions from the Sprig library (string manipulation, math, date formatting, etc.). Environment variable functions (env, expandenv) are explicitly removed for security.
Format Conversion - Custom functions for data transformation:
toYaml/fromYaml- YAML serializationtoJson/fromJson- JSON serializationtoToml/fromToml- TOML serializationmustToYaml/mustToJson- Panic on error variants
Helm-Specific Functions:
include- Include another template by nametpl- Render a string as a templaterequired- Enforce required valueslookup- Query Kubernetes cluster for existing resources
File Access
The .Files object provides template access to non-template chart files:
{{.Files.Get "config/app.conf"}} # Get file as string
{{.Files.GetBytes "data/binary"}} # Get raw bytes
{{.Files.Glob "config/**"}} # Match files by pattern
{{.Files.Glob "config/**" | .AsConfig}} # Convert to ConfigMap data
{{.Files.Glob "secrets/*" | .AsSecrets}} # Convert to Secret data (base64)
{{.Files.Lines "config/list.txt"}} # Split file into lines
Kubernetes Lookups
The lookup function queries the cluster for existing resources, enabling dynamic template generation:
{{lookup "v1" "Pod" "default" "my-pod"}} # Get single resource
{{lookup "v1" "Pod" "default" ""}} # List all pods in namespace
{{lookup "apps/v1" "Deployment" "" "my-deploy"}} # Cluster-scoped resource
Returns empty map if resource not found (allowing if not (lookup ...) patterns). Requires Kubernetes API access via RenderWithClient() or RenderWithClientProvider().
Rendering Modes
- Strict Mode - Template rendering fails if a template references undefined values
- Lint Mode - Allows missing required values for chart validation
- Custom Functions - Users can inject custom template functions via
Engine.CustomTemplateFuncs
Error Handling
Parse errors include filename and line number. Execution errors are reformatted with template location and function context. Missing values in non-strict mode render as empty strings (Go's <no value> is stripped).
Release Management & Storage
Relevant Files
pkg/storage/storage.gopkg/storage/driver/driver.gopkg/storage/driver/secrets.gopkg/storage/driver/cfgmaps.gopkg/storage/driver/memory.gopkg/storage/driver/sql.gopkg/action/install.gopkg/action/upgrade.gopkg/action/rollback.gopkg/action/action.go
Helm manages release state through a pluggable storage abstraction layer. Every deployment, upgrade, and rollback operation persists release metadata to a backend storage system, enabling history tracking, rollback capabilities, and concurrent operation safety.
Storage Architecture
The storage system is built on a driver-based abstraction that separates the storage interface from implementation details. The Storage struct wraps a Driver interface and provides high-level operations like Create(), Update(), Delete(), and Get(). Drivers implement the actual persistence logic for different backends.
Loading diagram...
Supported Storage Backends
Helm v4 supports four storage drivers, selectable via the HELM_DRIVER environment variable:
-
Secrets (default): Stores releases as Kubernetes Secrets in the release namespace. Each secret is labeled with metadata (name, version, status, owner).
-
ConfigMaps: Stores releases as Kubernetes ConfigMaps. Similar to Secrets but suitable for non-sensitive data and environments with Secret restrictions.
-
Memory: In-memory storage for testing and dry-run operations. Namespace-aware and reused across multiple operations within the same configuration.
-
SQL: Experimental support for SQL databases (PostgreSQL). Requires
HELM_DRIVER_SQL_CONNECTION_STRINGenvironment variable.
Release Storage Format
Releases are stored as base64-encoded, gzip-compressed protobuf messages. Each storage object includes:
- Key: Format
sh.helm.release.v1.{release-name}.v{version}(e.g.,sh.helm.release.v1.my-app.v3) - Type:
helm.sh/release.v1(Kubernetes object type field) - Labels: Metadata for querying (name, version, status, owner, timestamps)
- Body: Serialized release object containing chart, config, manifest, and hooks
Release Lifecycle & History Management
The Storage.Create() method enforces history limits via MaxHistory. When creating a new release, if the history exceeds the limit, the least recent release is automatically removed. This prevents unbounded storage growth while preserving rollback capability.
// Example: MaxHistory = 10 keeps the 10 most recent releases
if s.MaxHistory > 0 {
s.removeLeastRecent(name, s.MaxHistory-1)
}
Integration with Actions
Install, Upgrade, and Rollback actions interact with storage as follows:
- Install: Creates a new release (version 1) via
Releases.Create() - Upgrade: Creates a new release version via
Releases.Create(), incrementing the version number - Rollback: Retrieves a previous release via
Releases.Get(), then creates a new release with the previous manifest - Uninstall: Updates the release status to UNINSTALLED without deleting the record
Query operations like Deployed(), History(), and Last() filter releases by status and version to support listing and retrieval workflows.
Concurrency & Safety
The storage layer includes safeguards against concurrent operations. The Deployed() method detects and resolves concurrent deployments by selecting the latest revision. Kubernetes-backed drivers (Secrets/ConfigMaps) leverage Kubernetes' optimistic concurrency control via resource versions.
Plugin System & Extensibility
Relevant Files
internal/plugin/plugin.gointernal/plugin/loader.gointernal/plugin/runtime.gointernal/plugin/runtime_subprocess.gointernal/plugin/runtime_extismv1.gointernal/plugin/metadata.gopkg/cmd/plugin.gopkg/getter/plugingetter.gointernal/plugin/schema/
Helm's plugin system enables extensibility through a flexible architecture supporting multiple plugin types and runtimes. Plugins are discovered, loaded, and executed through a well-defined interface that abstracts away runtime details.
Plugin Architecture
The core plugin system is built on three key abstractions:
- Plugin Interface - Defines the contract for plugin instances with methods to retrieve metadata and invoke the plugin
- Runtime - Handles plugin instantiation and execution (subprocess, WebAssembly/Extism)
- Metadata - Describes plugin configuration, type, and runtime requirements
Plugins are defined by a plugin.yaml manifest file in their directory. The loader supports both legacy and v1 API versions, automatically converting them to a unified in-memory representation.
Plugin Types
Helm supports three primary plugin types, each with specific input/output schemas:
- CLI Plugins (
cli/v1) - Extend Helm with custom commands, receiving extra arguments and returning output data - Getter Plugins (
getter/v1) - Handle custom chart download protocols by implementing protocol-specific retrieval logic - Post-Renderer Plugins (
postrenderer/v1) - Transform rendered Kubernetes manifests before deployment
Each type defines its own input/output message structure and configuration schema through the internal/plugin/schema package.
Runtime Execution Models
Loading diagram...
Subprocess Runtime - Launches plugins as external processes, communicating via JSON over stdin/stdout. Supports platform-specific commands and lifecycle hooks (install, upgrade, uninstall).
Extism/WASM Runtime - Executes WebAssembly plugins in a sandboxed environment with configurable memory limits, HTTP access controls, and temporary filesystem support. Provides host functions for plugin-to-Helm communication.
Plugin Discovery & Loading
The LoadDir() function loads a single plugin from a directory, while LoadAll() scans a base directory for all plugins. The FindPlugins() function filters plugins by type and name using a descriptor pattern.
Plugin loading involves:
- Reading and parsing
plugin.yaml(supporting both legacy and v1 formats) - Validating metadata (name, type, runtime, configuration)
- Creating a runtime-specific plugin instance via the appropriate
Runtimeimplementation - Detecting duplicate plugin names across directories
Plugin Management Commands
The CLI provides commands for plugin lifecycle management:
helm plugin install- Install plugins from local paths, HTTP URLs, or OCI registrieshelm plugin list- Display installed pluginshelm plugin uninstall- Remove pluginshelm plugin update- Update existing pluginshelm plugin verify- Verify plugin signatureshelm plugin package- Package plugins for distribution
Installation supports optional signature verification and can extract plugins from various sources (local filesystem, HTTP, VCS, OCI).
Plugin Invocation
Plugins are invoked through the Invoke() method, which accepts a context, input message, and optional stdin/stdout/stderr streams. The input message is JSON-serializable and interpreted according to the plugin type. Plugins return output messages or execution errors.
Plugins can also implement the PluginHook interface to respond to lifecycle events (install, upgrade, uninstall) through the InvokeHook() method.
Registry & Chart Distribution
Relevant Files
pkg/registry/client.go- OCI registry client implementationpkg/registry/chart.go- Chart-specific registry operationspkg/getter/ocigetter.go- OCI chart retrieval handlerpkg/getter/httpgetter.go- HTTP repository handlerpkg/pusher/ocipusher.go- OCI chart push implementationpkg/downloader/chart_downloader.go- Chart download orchestrationpkg/uploader/chart_uploader.go- Chart upload orchestrationpkg/repo/v1/chartrepo.go- Traditional chart repository supportpkg/repo/v1/index.go- Repository index file handling
Helm supports two primary distribution mechanisms for charts: traditional HTTP repositories and modern OCI registries. This dual approach enables both legacy compatibility and cloud-native deployment patterns.
Traditional HTTP Repositories
Traditional chart repositories use HTTP(S) to serve charts and an index.yaml metadata file. The ChartRepository type in pkg/repo/v1/ manages repository configuration and index files. Each repository entry stores connection details: URL, credentials, TLS certificates, and authentication settings.
The HTTPGetter retrieves charts and index files over HTTP(S), handling authentication via basic auth or custom headers. Repository indexes are cached locally and parsed to resolve chart versions and download URLs. The ChartDownloader orchestrates the full download flow, including verification against provenance files when requested.
OCI Registry Support
OCI-compliant registries (Docker registries, Artifactory, Harbor, etc.) provide a modern alternative using the OCI Image Spec. The Client in pkg/registry/ implements OCI operations with ORAS (OCI Repository As Storage) as the underlying library.
Key OCI Concepts:
- References: Charts are addressed as
registry.example.com/myapp/mychart:1.0.0 - Layers: Charts are stored as OCI image layers with specific media types
- Media Types: Helm defines custom types for chart content, config, and provenance data
- Credentials: Uses Docker config.json or environment variables for authentication
Chart Push & Pull Operations
// Pull downloads a chart from an OCI registry
result, err := client.Pull("registry.example.com/myapp/mychart:1.0.0",
registry.PullOptWithChart(true),
registry.PullOptWithProv(true))
// Push uploads a chart to an OCI registry
result, err := client.Push(chartBytes, "registry.example.com/myapp/mychart:1.0.0",
registry.PushOptProvData(provBytes))
The OCIGetter handles chart retrieval by delegating to the registry client. The OCIPusher handles uploads, validating chart metadata and constructing proper OCI references. Both support TLS configuration, plain HTTP mode, and credential management.
Unified Download & Upload Interface
The ChartDownloader and ChartUploader provide scheme-agnostic interfaces. They detect the URL scheme (http, https, or oci) and route to the appropriate handler. This abstraction allows commands like helm pull and helm push to work seamlessly across repository types without knowing implementation details.
Loading diagram...
Authentication & Security
Both mechanisms support TLS certificates, basic authentication, and credential stores. OCI registries leverage Docker's credential helpers for secure credential storage. HTTP repositories support per-repository credentials and optional credential pass-through to dependency charts. The registry client handles OAuth2 flows for cloud registries automatically.
Version Handling
OCI tags have restrictions (no + character), so Helm converts semantic version pre-release identifiers: 1.0.0+build123 becomes 1.0.0_build123 when pushing and converts back when pulling. This ensures compatibility with OCI tag specifications while preserving version semantics.