Helm Library Charts
Library charts provide reusable templates and utilities that can be shared across multiple charts. They are not installable on their own.
Overview
A library chart is a type of Helm chart that:
- Defines chart primitives or shared definitions
- Cannot be deployed independently
- Is included as a dependency by application charts
- Allows template code reuse across charts
Creating a Library Chart
1. Create Chart Structure
helm create common-lib --type libraryThis creates:
common-lib/
├── Chart.yaml
├── templates/
└── values.yaml
2. Configure as Library
# Chart.yaml
apiVersion: v2
name: common-lib
description: Common library chart with shared templates
type: library
version: 1.0.0
appVersion: "1.0.0"3. Remove Installable Resources
Delete all template files and start fresh:
rm -rf common-lib/templates/*4. Create Shared Templates
_configmap.tpl
{{/* Common ConfigMap template */}}
{{- define "common.configmap" -}}
{{- $fullName := include "common.fullname" . -}}
{{- $labels := include "common.labels" . -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ $fullName }}
labels:
{{- $labels | nindent 4 }}
{{- end -}}_deployment.tpl
{{/* Common Deployment template */}}
{{- define "common.deployment" -}}
{{- $name := include "common.fullname" . -}}
{{- $labels := include "common.labels" . -}}
{{- $selector := include "common.selectorLabels" . -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $name }}
labels:
{{- $labels | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount | default 1 }}
selector:
matchLabels:
{{- $selector | nindent 6 }}
template:
metadata:
labels:
{{- $selector | nindent 8 }}
{{- end -}}_service.tpl
{{/* Common Service template */}}
{{- define "common.service" -}}
{{- $name := include "common.fullname" . -}}
{{- $labels := include "common.labels" . -}}
{{- $selector := include "common.selectorLabels" . -}}
apiVersion: v1
kind: Service
metadata:
name: {{ $name }}
labels:
{{- $labels | nindent 4 }}
spec:
type: {{ .Values.service.type | default "ClusterIP" }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort | default "http" }}
protocol: TCP
name: http
selector:
{{- $selector | nindent 4 }}
{{- end -}}_helpers.tpl
{{/* Full name (release-chart) */}}
{{- define "common.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | printf "%s" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{/* Full labels including release info */}}
{{- define "common.labels" -}}
app.kubernetes.io/name: {{ include "common.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
{{- end -}}
{{/* Selector labels (for pod selector) */}}
{{- define "common.selectorLabels" -}}
app.kubernetes.io/name: {{ include "common.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{/* Chart name */}}
{{- define "common.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/* Merge utility - merges two YAML maps */}}
{{- define "common.merge" -}}
{{- $overrides := .Values | deepCopy -}}
{{- toYaml (merge $overrides (include .template $.context | fromYaml)) -}}
{{- end -}}_util.yaml
{{/* Utility: Merge two YAML templates */}}
{{- define "util.merge" -}}
{{- $top := first . -}}
{{- $overrides := fromYaml (include (index . 1) $top) | default dict -}}
{{- $tpl := fromYaml (include (index . 2) $top) | default dict -}}
{{- toYaml (merge $overrides $tpl) -}}
{{- end -}}
{{/* Utility: Conditional default */}}
{{- define "util.default" -}}
{{- if empty (index .Values (index . 1)) -}}
{{- print (index . 2) -}}
{{- else -}}
{{- print (index .Values (index . 1)) -}}
{{- end -}}
{{- end -}}Using Library Charts
Add as Dependency
# Chart.yaml
dependencies:
- name: common-lib
version: "1.x.x"
repository: "file://../common-lib"
# Or from registry:
# repository: "oci://ghcr.io/org/charts/common-lib"Run Dependency Update
helm dependency update ./myappUse Shared Templates
# templates/configmap.yaml
{{- include "common-lib.configmap" (list . "myapp.configmap") -}}
{{- define "myapp.configmap" -}}
data:
app.ini: |
[settings]
log_level = {{ .Values.config.logLevel | default "info" }}
max_connections = {{ .Values.config.maxConnections | default 1000 }}
{{- end -}}Override Defaults
# templates/deployment.yaml
{{- $ctx := dict "Release" .Release "Chart" .Chart "Values" .Values "Template" .Template -}}
{{- $deployment := include "common-lib.deployment" $ctx -}}
{{- $tpl := fromYaml $deployment -}}
{{- $_ := set $tpl.spec "replicas" .Values.replicaCount -}}
{{- $_ := set $tpl.spec.template.spec "restartPolicy" "Always" -}}
{{- toYaml $tpl | nindent 0 -}}Utility Functions for Library Charts
DeepMerge
{{/* _utils.tpl */}}
{{/* Deep merge two YAML structures */}}
{{- define "utils.deepMerge" -}}
{{- $dst := index . 0 -}}
{{- $src := index . 1 -}}
{{- if kindOf "map" eq $dst }}
{{- range $key, $value := $src }}
{{- if and (hasKey $dst $key) (kindIs "map" (index $dst $key)) }}
{{- $_ := set $dst $key (include "utils.deepMerge" (list (index $dst $key) $value)) }}
{{- else }}
{{- $_ := set $dst $key $value }}
{{- end }}
{{- end }}
{{- end }}
{{- toYaml $dst -}}
{{- end -}}Template Include with Context
{{/* _utils.tpl */}}
{{/* Include template with modified context */}}
{{- define "utils.withValues" -}}
{{- $values := index . 1 -}}
{{- $template := index . 0 -}}
{{- $ctx := merge .Values $values -}}
{{- include $template (dict "Values" $ctx "Release" .Release "Chart" .Chart "Template" .Template) -}}
{{- end -}}Best Practices
1. Use Named Templates with Prefix
# Prefix with chart name to avoid conflicts
{{- define "common-lib.configmap" -}}
# ...
{{- end -}}
{{- define "common-lib.deployment" -}}
# ...
{{- end -}}2. Provide Default Values
# values.yaml in library chart
replicaCount: 1
image:
repository: nginx
tag: "latest"
service:
type: ClusterIP
port: 80
config:
logLevel: info3. Document Template Usage
# _README.md in templates/
{{/*
Common utility templates for Kubernetes resources.
Usage:
{{ include "common-lib.configmap" (list . "myapp.configmap") }}
{{- define "myapp.configmap" -}}
data:
key: value
{{- end -}}
*/}}4. Version Carefully
# Library chart should follow SemVer strictly
version: 1.0.0 # Major for breaking changes
version: 1.1.0 # Minor for new features
version: 1.0.1 # Patch for bug fixes5. Test Library Charts
# templates/tests/configmap_test.yaml
apiVersion: v1
kind: Pod
metadata:
name: {{ include "common-lib.fullname" . }}-test
annotations:
helm.sh/hook: test
spec:
containers:
- name: test
image: busybox
command: ['echo', 'Library chart works']
restartPolicy: NeverExample: Shared Monitoring Template
common-lib/templates/_servicemonitor.tpl
{{/* ServiceMonitor for Prometheus scraping */}}
{{- define "common.servicemonitor" -}}
{{- $name := include "common.fullname" . -}}
{{- $labels := include "common.labels" . -}}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ $name }}
labels:
{{- $labels | nindent 4 }}
prometheus: {{ .Values.prometheus.scrape | default "true" }}
spec:
jobLabel: {{ $name }}
selector:
matchLabels:
{{- include "common.selectorLabels" . | nindent 6 }}
endpoints:
- port: http
path: {{ .Values.prometheus.path | default "/metrics" }}
interval: {{ .Values.prometheus.interval | default "30s" }}
{{- end -}}Usage in Application Chart
# myapp/templates/servicemonitor.yaml
{{- if .Values.monitoring.enabled -}}
{{- include "common-lib.servicemonitor" . }}
{{- end -}}Installation Prevention
Library charts cannot be installed directly:
$ helm install common-lib ./common-lib
Error: library charts are not installableThis is intentional - they only provide utility templates for other charts.