Values reference
values.yaml at the chart root carries machine-readable defaults only — no inline comments. This page is the annotated reference: a topical index of every top-level key grouped by feature, with cross-links to the relevant ADR and example folder, plus a cross-cutting rules cheatsheet for behaviours that span multiple keys.
For the schema’s machine-checkable shape, see 02-schema.md. For supported Kubernetes / CRD versions, see 03-compatibility.md. For a complete working example with every chart feature enabled (passes helm template), see values.yaml.example at the chart root.
Topical index
| Topic | Top-level keys | Read more |
|---|---|---|
| Identity & metadata | commonLabels, commonAnnotations, labels.standard, nameOverride, fullnameOverride, naming.omitWorkloadSuffix | ADR 011 · ADR 021 |
| Environment & config | global.env, env, envSecrets, envConfigMaps, configMaps, podAnnotations, jobPodAnnotations | ADR 003 · ADR 015 |
| Image & pulls | image, imagePullSecrets, jobCompletionImage | 02-examples/01-minimal/ |
| Deployments / StatefulSets | deployments, statefulSets, strategy, statefulSetUpdateStrategy, revisionHistoryLimit, progressDeadlineSeconds, minReadySeconds | ADR 002 · 02-examples/03-statefulset-pvc/ |
| Per-pod containers | per-workload initContainers, sidecars | ADR 002 · ADR 014 · 02-examples/10-init-containers/ |
| Job groups | jobGroups | ADR 005 · ADR 012 · 02-examples/05-cronjobs/ |
| Networking — Ingress | ingress (hosts, tls as native k8s list, defaultBackend), ingresses | ADR 009 · 02-examples/02-web-app-ingress/ |
| Networking — Gateway API | httpRoute, httpRoutes, grpcRoute, grpcRoutes, tlsRoute, tlsRoutes, referenceGrant, referenceGrants | ADR 009 · 02-examples/04-gateway-api/ |
| Autoscaling | per-workload hpa, keda, verticalPodAutoscaler | ADR 007 · 02-examples/08-keda-event-driven/ |
| Monitoring | integrations.monitoring.defaults, per-workload metrics, auto-exposed metrics port | ADR 008 · ADR 016 · 02-examples/06-monitoring/ |
| Secrets (ESO) | integrations.eso.enabled, integrations.eso.secretStores, integrations.eso.externalSecrets | ADR 015 · 02-examples/07-external-secrets/ |
| Identity & RBAC | serviceAccount (create defaults to true), rbac (enabled, clusterScoped, rules), automountServiceAccountToken | 02-examples/07-external-secrets/ |
| Pod-level policies | podSecurityContext, securityContext, resources (root-level defaults: cpu: 10m, memory: 32Mi), terminationGracePeriodSeconds, podDisruptionBudget, topologySpreadConstraints (native k8s list), priorityClassName, nodeSelector, affinity, tolerations, hostAliases | — |
| Volumes | volumes, volumeMounts (root-level maps; per-workload override) | ADR 004 |
| Argo CD integrations | integrations.argocd.syncWaves, integrations.argocd.imageUpdater | ADR 010 |
| Stakater Reloader | integrations.stakater.reloader | ADR 017 |
For a working configuration in each area, follow the example links above. For the full value shape, see values.schema.json.
Cross-cutting rules
The behaviours below span multiple keys; reading the values.yaml comment on any single one doesn’t tell you the whole story.
Environment variable merge order
For each container, env is composed in this order (later layers win on key collision; non-colliding keys union):
NAMESPACE (fieldRef) → global.env → env → workload.env → container.env
Per-workload opt-out: inherit.env.{global,root}: false (skip env layers), inherit.envSecrets: false (exclude root envSecrets from envFrom), inherit.configMaps: false (skip root envConfigMaps). See ADR 003.
Label precedence on workload resources
app.kubernetes.io/nameandapp.kubernetes.io/instanceare always emitted on workload selectors and pod template labels, regardless of any toggle. The Kubernetes API forbids selector mutation; the chart guarantees they’re present.commonLabelscannot shadow chart-managedapp.kubernetes.io/*keys — chart values silently win.labels.standard.{partOf,version,managedBy,enabled}toggles affect singletons (ServiceAccount, Ingress, Routes, etc.) but not workload selectors.
See ADR 011.
Port ordering inside Service / pod template
When a workload’s service.ports (or per-container ports) is iterated:
http (if present) → others alphabetically → metrics (if present)
Auto-injected metrics port (from integrations.monitoring.defaults.exposeService) lands last. See ADR 014 and ADR 016.
The single-port service form
A workload’s Service takes ports either as the service.ports.<name> map or as the shorthand pair service.port / service.targetPort. In the shorthand, each side falls back to the other, in the Service and in the container spec alike:
service:
enabled: true
port: 80 # container listens on 80 as well
service:
enabled: true
port: 80
targetPort: 8080 # container listens on 8080
The map form falls back the same way: service.ports.<name>.port alone is enough, and the container port follows it. An entry with neither key has nothing to fall back to and fails the render:
service.ports for workload "web": port "http" declares neither port nor
targetPort. Set port, or a numeric targetPort for it to fall back to.
The fallback runs one way only. spec.ports[].port is a number, so an entry that names its targetPort has to declare port itself:
service.ports for workload "web": port "grpc" names its targetPort "grpc"
and declares no port. A Service port is a number and cannot fall back to a
name, so set port explicitly.
An enabled Service with neither form, and no metrics port injected by integrations.monitoring.defaults.exposeService, fails the render. A client-facing Service has nothing sensible to default to, unlike headlessService, which falls back to port 80 because a StatefulSet needs its governing Service to exist at all. The exception is type: ExternalName, which resolves to a DNS name, carries no virtual IP and so needs no ports; a portless one renders without a ports block, and any ports it does declare are still passed through.
Named targetPort and the workload ports map
A Service targetPort may name a port instead of numbering it. containerPort is an integer, so the chart derives container ports from numeric targets only: a named targetPort is passed through to the Service as written and adds nothing to the container spec. Kubernetes resolves the name against whichever container in the Pod declares it.
Declare the port on the container that serves it. A workload’s own ports map replaces the Service-derived container ports entirely, which leaves the Service free to refer to the port by name:
deployments:
web:
ports:
grpc:
containerPort: 9000
service:
enabled: true
ports:
grpc:
port: 9000
targetPort: grpc
A sidecar can serve it as well. A Service port whose targetPort names a port one of the workload’s sidecars declares belongs to that sidecar’s container, and the main container leaves it out:
deployments:
web:
service:
ports:
http:
port: 80
targetPort: 8080 # containerPort on the web container
proxy:
port: 9000
targetPort: envoy-admin
sidecars:
envoy:
image:
repository: envoyproxy/envoy
tag: v1.31-latest
ports:
envoy-admin:
containerPort: 9901 # the port the Service name resolves to
The chart does not check that some container declares the name. A container added by an admission webhook — a service-mesh proxy, for one — declares ports no values key describes, and a Service may target those by name:
deployments:
web:
ports:
http:
containerPort: 8080
service:
ports:
http:
port: 80
targetPort: http
envoy-prom:
port: 15090
targetPort: http-envoy-prom # declared by the injected proxy
A name nothing in the Pod declares leaves that Service port without endpoints, so a typo shows up as an empty kubectl get endpointslices rather than as a render error.
Service port appProtocol
Both Service port shapes accept an optional appProtocol — the single-port service.port/service.targetPort form and the service.ports.<name> map form (and their headlessService equivalents on StatefulSets). It passes straight through to spec.ports[].appProtocol, the native Kubernetes Service field.
Set it when a port speaks something other than plain HTTP/1.1 and the consumer needs to know — most commonly kubernetes.io/h2c on a gRPC port, so a Gateway API implementation routing a GRPCRoute to that Service configures the upstream connection as HTTP/2 cleartext instead of assuming HTTP/1.1:
service:
ports:
grpc:
port: 9000
targetPort: 9000
appProtocol: kubernetes.io/h2c
Dropping the workload suffix from names
Every per-workload resource is named <fullname>-<workloadName>, and the workload name also lands in app.kubernetes.io/name while app.kubernetes.io/instance carries the full construction. A release that runs one workload can drop that suffix:
naming:
omitWorkloadSuffix: true # default: false
With it on, a release named myrel renders myrel-universal-helm-chart for the Deployment, the Service, the HPA, the PDB, the VPA, the ScaledObject and the NetworkPolicy, and keeps the usual trailing parts elsewhere: -headless, -metrics, -config. Labels and selectors follow: app.kubernetes.io/name becomes the chart name (nameOverride when set) and app.kubernetes.io/instance becomes <fullname>.
Note that <fullname> is not what singleton resources carry. uhc.labels puts app.kubernetes.io/instance: <release name> on the ServiceAccount, Ingress and Routes, and that stays as it is. So a release myrel gives the Deployment instance: myrel-universal-helm-chart and the ServiceAccount instance: myrel. A kubectl -l selector, or an external ServiceMonitor, has to pick the one it means.
Three things stay where they are.
Container names keep the workload key, so kubectl logs -c api still works and KEDA’s envSourceContainerName still resolves.
jobGroups keep both their names and their labels. The names are built from the group and job keys and never carried a workload suffix; the labels stay on <groupName>-<jobName> / <fullname>-<groupName>-<jobName> because a release can hold any number of job groups next to its one workload. Collapsing them would file every Job pod under the workload’s own selector, and the workload’s Service, NetworkPolicy and PDB would then pick up job pods.
ESO SecretStore and ExternalSecret entries keep their own keys in labels for the same reason.
The flag expects exactly one enabled entry across deployments and statefulSets. With more than one, helm template fails and names the offenders rather than collapsing them onto the same resource names:
naming.omitWorkloadSuffix expects exactly one enabled workload, found 2
(deployments.api, deployments.worker).
Turning the flag on or off for a release that already exists renames its workload and changes an immutable selector, so the Deployment or StatefulSet is replaced rather than updated. Decide before the first install. See ADR 021.
Service naming
A workload’s Service is named <fullname>-<workloadName>. service.nameOverride replaces that name:
deployments:
frontend:
service:
enabled: true
nameOverride: frontend-web
The override covers the Service object and every chart-rendered reference that defaults to it — Gateway API backendRefs in httpRoute / grpcRoute / tlsRoute rules that carry no explicit serviceName. Labels and selectors are untouched: app.kubernetes.io/name and app.kubernetes.io/instance keep the workload’s own values, so the Service still selects the same pods. The metrics-only Service rendered for a workload that has no Service of its own keeps its <fullname>-<workloadName>-metrics name.
On a StatefulSet the governing headless Service has its own key, headlessService.nameOverride, and spec.serviceName follows it. With headlessService.enabled: false that key is required and names the externally managed Service providing stable per-pod DNS. statefulSets.<name>.serviceName is the older spelling of the same value and still works; headlessService.nameOverride wins when both are set.
Either override is checked against the 63-character ceiling the chart applies to every constructed name, and against the other Services in the release. Two workloads resolving to one Service name, or a StatefulSet whose client and headless Services land on the same name, fail the render:
Service name "shared-svc" is claimed by both deployments.a.service
and deployments.b.service.
headlessService.enabled: false is the one case allowed to look like a collision, because the name usually belongs to a Service outside the release. The one name inside it that also works is the workload’s own client Service with clusterIP: None, which is headless and already selects these pods. Anything else the chart renders leaves spec.serviceName on a Service that never provides per-pod DNS, and the render fails:
statefulSets.db.headlessService is disabled, so spec.serviceName points at
"shared" — but that name belongs to statefulSets.db.service, a Service this
chart renders itself.
jobGroups group → job merge
For each per-job field:
- maps (env, podAnnotations, metadataAnnotations) — replace per key; later wins.
- lists (envSecrets, envConfigMaps, tolerations) — concat.
- topologySpreadConstraints — the job list replaces the group list, and either replaces the root list. Kubernetes rejects two constraints with the same
topologyKeyandwhenUnsatisfiable, so the lists are never concatenated.topologySpreadConstraints: []on a group or job opts out. - volumes / volumeMounts — replace by name (a volume can’t be partially
emptyDirand partiallyconfigMap).
hashSuffix: true together with a delete-policy that removes the Job after success is rejected fail-fast — the Job would re-run on every sync. See ADR 005 and ADR 012.
HTTPRoute rule fields (name, timeouts, retry, sessionPersistence)
Every HTTPRoute rule (in httpRoute.rules, httpRoutes.<n>.rules, and per-workload deployments.<w>.httpRoute.rules / statefulSets.<w>.httpRoute.rules) accepts four optional field groups beyond matches, filters, and backendRefs:
| Field | Type | Description |
|---|---|---|
name | string (SectionName: lowercase RFC 1123 label, optionally dotted, max 253 chars) | Identifies the rule. Surfaced in Gateway API status conditions, access logs, and distributed traces. MUST be unique within the route. |
timeouts.request | string (Gateway API Duration, GEP-2257) | Total time budget for the complete HTTP request/response cycle, measured from when the gateway forwards the request. "0s" disables the timeout. Example: "30s". |
timeouts.backendRequest | string (Gateway API Duration) | Time budget for the backend to process the request. Must be ≤ timeouts.request. Example: "10s". |
retry.attempts | integer (≥ 0) | Maximum number of retry attempts. |
retry.codes | array of integer (400–599) | HTTP status codes that trigger a retry (e.g. [503, 504]). Implementations MUST support 500/502/503/504 as retriable. |
retry.backoff | string (Gateway API Duration) | Minimum wait between retry attempts. Example: "1s". |
sessionPersistence.sessionName | string (1–128 chars) | Identifier the implementation uses for the persistence value (cookie name or header name, depending on type). |
sessionPersistence.type | enum: Cookie | Header | Persistence mechanism. Defaults to Cookie server-side when omitted. |
sessionPersistence.absoluteTimeout | string (Gateway API Duration) | Maximum lifetime of the session, regardless of activity. Example: "1h". |
sessionPersistence.idleTimeout | string (Gateway API Duration) | Maximum idle time before the session expires. Example: "10m". |
sessionPersistence.cookieConfig.lifetimeType | enum: Permanent | Session | Cookie lifetime style (relevant only when type: Cookie). |
All four field groups are optional and independently combinable — you can set timeouts without retry, or name without either. Fields absent from a rule are omitted from the rendered manifest; they do not inherit from sibling rules or the route root.
Schema strictness. Each rule entry is validated against a strict schema (
additionalProperties: false) listing only the fields above plusmatches,filters,backendRefs,serviceName, andservicePort. Unknown keys (typos, deprecated fields, or Gateway API fields not yet wired into the chart) fail athelm templatetime with a clear validation error rather than being silently dropped. If you depend on a Gateway API HTTPRouteRule field not in this list, open an issue or submit a PR — see ADR 009.
Gateway API channel and version requirements
The chart’s CRD-channel detection runs at template time when gateway.networking.k8s.io/v1 is present in Capabilities.APIVersions and emits a fail-fast error if the field’s required CRD channel is missing. Detection is skipped when rendering offline (helm template without --api-versions).
| Field | Minimum Gateway API | Channel | Detection marker |
|---|---|---|---|
name | v1.4.0 (Standard) or v1.2.0+ (Experimental) | Standard since v1.4.0; Experimental from v1.2 to v1.3 | gateway.networking.k8s.io/v1/BackendTLSPolicy (Standard, graduated in v1.4.0) or gateway.networking.k8s.io/v1alpha2/TCPRoute (Experimental) |
timeouts.* | v1.2.0 | Standard | none — implied by gateway.networking.k8s.io/v1 |
retry.* | v1.2.0 | Experimental only (still Experimental as of v1.5.1) | gateway.networking.k8s.io/v1alpha2/TCPRoute (Experimental) |
sessionPersistence.* | v1.2.0 | Experimental only (still Experimental as of v1.5.1) | gateway.networking.k8s.io/v1alpha2/TCPRoute (Experimental) |
If your cluster runs Standard channel CRDs older than v1.4 and you need name, you must install the Experimental channel; if you need retry or sessionPersistence at all, you must install the Experimental channel — Standard CRDs reject those fields.
See the 04-gateway-api example for a working configuration and Gateway API’s release channels for installation guidance.
GRPCRoute rule fields (name, sessionPersistence)
Every GRPCRoute rule (in grpcRoute.rules, grpcRoutes.<n>.rules, and per-workload deployments.<w>.grpcRoute.rules / statefulSets.<w>.grpcRoute.rules) accepts two optional field groups beyond matches, filters, and backendRefs:
| Field | Type | Description |
|---|---|---|
name | string (SectionName: lowercase RFC 1123 label, optionally dotted, max 253 chars) | Identifies the rule. Surfaced in Gateway API status conditions and traces. MUST be unique within the route. |
sessionPersistence.sessionName | string (1–128 chars) | Identifier the implementation uses for the persistence value (cookie name or header name, depending on type). |
sessionPersistence.type | enum: Cookie | Header | Persistence mechanism. Defaults to Cookie server-side when omitted. |
sessionPersistence.absoluteTimeout | string (Gateway API Duration) | Maximum lifetime of the session, regardless of activity. Example: "1h". |
sessionPersistence.idleTimeout | string (Gateway API Duration) | Maximum idle time before the session expires. Example: "10m". |
sessionPersistence.cookieConfig.lifetimeType | enum: Permanent | Session | Cookie lifetime style (relevant only when type: Cookie). |
Both groups are independently optional. GRPCRouteRule has no timeouts or retry — those are HTTPRoute-only fields in the Gateway API spec.
Schema strictness. Each rule entry is validated against a strict schema (
additionalProperties: false) listing onlyname,matches,filters,backendRefs,serviceName,servicePort, andsessionPersistence. Unknown keys fail athelm templatetime.
Gateway API channel and version requirements
| Field | Minimum Gateway API | Channel | Detection marker |
|---|---|---|---|
name | v1.4.0 (Standard) or v1.2.0+ (Experimental) | Standard since v1.4.0; Experimental from v1.2 to v1.3 | gateway.networking.k8s.io/v1/BackendTLSPolicy (Standard, graduated in v1.4.0) or gateway.networking.k8s.io/v1alpha2/TCPRoute (Experimental) |
sessionPersistence.* | v1.2.0 | Experimental only (still Experimental as of v1.5.1) | gateway.networking.k8s.io/v1alpha2/TCPRoute (Experimental) |
The chart fails fast at helm template time when gateway.networking.k8s.io/v1 is present but the required channel marker is not. Detection is skipped offline (helm template without --api-versions).
TLSRoute rule fields (name)
Every TLSRoute rule (in tlsRoute.rules, tlsRoutes.<n>.rules, and per-workload deployments.<w>.tlsRoute.rules / statefulSets.<w>.tlsRoute.rules) accepts one optional field beyond backendRefs:
| Field | Type | Description |
|---|---|---|
name | string (SectionName: lowercase RFC 1123 label, optionally dotted, max 253 chars) | Identifies the rule. MUST be unique within the route. |
TLSRouteRule has no matches, filters, timeouts, retry, or sessionPersistence — TLS is L4 passthrough; the spec defines only name and backendRefs.
Schema strictness. Each rule entry is validated against a strict schema (
additionalProperties: false) listing onlyname,backendRefs,serviceName, andservicePort. Unknown keys fail athelm templatetime.
TLSRoute itself is in the Gateway API Experimental channel (gateway.networking.k8s.io/v1alpha2), so any use of TLSRoute already presupposes Experimental CRDs — name adds no further channel requirement beyond TLSRoute itself.
Autoscaler mutual exclusion
hpa.enabled: trueandkeda.enabled: trueon the same workload is fail-fast. Both managespec.replicas; both running is undefined behaviour.verticalPodAutoscaleris orthogonal to both (touchesresources.requests, notreplicas).- When any HPA-class scaler is on,
spec.replicasis omitted from the rendered manifest so Helm doesn’t bounce the count on every apply.
See ADR 007.
KEDA advanced pass-through
keda.advanced goes into the ScaledObject’s spec.advanced verbatim. The chart checks that it is an object and stops there, so restoreToOriginalReplicaCount, horizontalPodAutoscalerConfig (name, behavior) and scalingModifiers all work, and so does anything KEDA adds later without a chart release in between.
deployments:
worker:
keda:
enabled: true
maxReplicas: 20
triggers:
- type: kafka
metadata: {...}
advanced:
restoreToOriginalReplicaCount: true
horizontalPodAutoscalerConfig:
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 1
periodSeconds: 60
behavior is the Kubernetes HPA scaling-behavior shape, applied to the HPA that KEDA creates. It is worth setting on a lag-driven trigger: the HPA default doubles the replica count every 15 seconds, which overshoots on a queue that drains quickly. The example above adds one pod a minute instead.
Because nothing here is validated field by field, a typo inside advanced reaches the cluster and is rejected by the KEDA CRD rather than by helm template. Check the field names against the ScaledObject spec for the KEDA version you run.
Scheduling field inheritance
tolerations, affinity, nodeSelector and topologySpreadConstraints all follow the same rule: if the workload defines the field, it replaces the root value entirely. If the workload omits the field, the root value is inherited. To disable root inheritance without providing a replacement, set the field to an empty value (tolerations: [], affinity: {}, topologySpreadConstraints: []).
Topology spread constraint fields
Each entry of topologySpreadConstraints (root, deployments.<name>, statefulSets.<name>, jobGroups.<group> and jobGroups.<group>.jobs.<job>) accepts the Kubernetes fields below and nothing else; an unknown key fails schema validation.
| Field | Required | Notes |
|---|---|---|
maxSkew | yes | Integer, 1 or more. |
topologyKey | yes | Node label key. |
whenUnsatisfiable | yes | DoNotSchedule or ScheduleAnyway. |
labelSelector | no | Defaults to the workload’s selector labels when omitted or empty. |
matchLabelKeys | no | List of pod label keys, e.g. pod-template-hash to spread each Deployment revision on its own. |
minDomains | no | Integer, 1 or more. Kubernetes accepts it only with whenUnsatisfiable: DoNotSchedule, and so does the schema. |
nodeAffinityPolicy | no | Honor or Ignore. Kubernetes treats an unset value as Honor. |
nodeTaintsPolicy | no | Honor or Ignore. Kubernetes treats an unset value as Ignore, so domains made only of tainted nodes still count toward the skew. |
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
minDomains: 3
nodeTaintsPolicy: Honor
matchLabelKeys:
- pod-template-hash
PodDisruptionBudget: minAvailable vs maxUnavailable
A PodDisruptionBudget takes one of the two. A workload-level podDisruptionBudget block replaces the root block as a whole, so it carries only what it states: setting both there fails with podDisruptionBudget for workload "<name>": cannot set both minAvailable and maxUnavailable, and a block with neither renders maxUnavailable: 1.
The root block always contains the chart default minAvailable: 1. A root maxUnavailable takes precedence over minAvailable, whether that is the default or a value you set:
podDisruptionBudget:
enabled: true
maxUnavailable: 1 # rendered; minAvailable is ignored
maxUnavailable: 0 and minAvailable: "100%" allow no voluntary evictions: kubectl drain and node autoscalers wait on those pods until the budget changes. The same holds for minAvailable: 1 on a single-replica workload.
Init containers and sidecars share one container shape
deployments.<name>.initContainers and deployments.<name>.sidecars (same under statefulSets.<name>) are maps keyed by container name. Both flow through the same renderer as the main container: image, command/args, env, envSecrets, volumeMounts, resources, securityContext, lifecycle. Both inherit the parent workload’s inherit.env / inherit.configMaps / inherit.configMapMount flags. Neither inherits root-level volumeMounts.<containerName> — declare local mounts inline. Render order is sortAlpha; for initContainers Kubernetes runs them sequentially in declared order, so prefix names with 01-, 02-, … when run order matters (same convention as jobGroups[*].tasks). Reloader does not re-trigger init containers — they run only on Pod creation, so a config change rolls the workload and a fresh init pass runs. Two exceptions for initContainers: probesEnabled / probe blocks (readinessProbe, livenessProbe, startupProbe) and lifecycle are rejected — Kubernetes does not allow these on standard init containers, so helm template fail-fasts if either is set on an init entry.
ConfigMap names
A workload with createConfigmap: true gets <fullname>-<workloadName>-config, and an entry in configMaps gets <fullname>-<key>. The two shapes meet whenever a key spells out the other’s suffix, so configMaps.web-config beside a workload named web lands both on one name, and under naming.omitWorkloadSuffix a key of just config is enough. That fails the render rather than producing two documents Kubernetes will refuse:
ConfigMap name "myrel-universal-helm-chart-web-config" is claimed by both
deployments.web.createConfigmap and configMaps.web-config.
The same check covers a deployments.<name> and a statefulSets.<name> sharing a key while both set createConfigmap. Disabled workloads and configMaps entries are ignored, since neither renders.
Chart-owned vs external name resolution
When the same name appears in both a chart-owned map (configMaps, integrations.eso.externalSecrets) and an external reference list (envConfigMaps, envSecrets):
- chart-owned wins: the rendered reference points at
<release-fullname>-<name>. - external is silently shadowed.
- having both with the same name is a smell — pick distinct names.
See ADR 015.
Where to go next
- Concrete configurations to copy →
02-examples/. - Why a specific shape was chosen →
05-adr/. - IDE-side schema validation →
02-schema.md. - Cluster / CRD requirements →
03-compatibility.md.