skip to content

In Kubernetes, what does setting `immutable: true` on a ConfigMap or Secret actually do, and why would a team turn it on?

level: middleimportance: should knowfreq 34%

answer

  1. one-way boolean; cannot unset
  2. data frozen, metadata still editable
  3. delete+recreate is the only edit
  4. kubelet skips the watch → API-server relief
  5. GA since 1.21

basics

~20 s

The API server then rejects any change to that object's data (and to the flag itself); only metadata like labels can change, and the only way to alter values is to delete and recreate the object. You get accident protection plus much lower kubelet/API-server watch load.

solid answer

~50 s

`immutable: true` is a field on ConfigMap and Secret. Once set, the API server rejects any update that touches `data`, `binaryData` or `stringData`, and it rejects unsetting the flag itself. Mutable metadata (labels, annotations) can still change, and you can still delete the whole object. So the only way to change a value is delete + recreate, or — much better — create a new, differently named object and point workloads at it. Two reasons to use it. First, safety: an in-place `kubectl edit` on a shared ConfigMap silently changes configuration under running Pods that mount it, with no rollout, no audit-friendly version and no easy rollback; immutability forces the change through a new object and a normal rollout. Second, scale: the kubelet does not have to watch immutable objects for changes, which removes a large number of watches from the API server in clusters with many ConfigMaps and Secrets. The feature has been GA since Kubernetes 1.21.

code

yaml · 10 lines
yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-7f2c1a
  labels:
    app: checkout
data:
  LOG_LEVEL: info
  FEATURE_X: "true"
immutable: true

go deeper

for a junior

Know the one-line meaning: the data can never be edited again, you delete and recreate instead, and the flag cannot be turned off.

for a middle

Add the two motivations — accidental-edit protection and reduced kubelet watch load — and note that metadata stays editable while data does not.

for a senior

Frame it as a change-control mechanism: config changes become versioned rollouts with rollback, and call out the tooling that breaks (controllers that write Secrets in place).

for a principal

Discuss it as a fleet policy: naming/hashing convention, garbage collection of superseded objects, and the API-server scalability numbers that justify mandating it.

## The field Both `ConfigMap` and `Secret` have a top-level boolean field `immutable`. It defaults to absent/false. You can set it at creation time, or patch it onto an existing mutable object exactly once. After that the object is frozen. ```yaml apiVersion: v1 kind: ConfigMap metadata: name: app-config-7f2c1a data: LOG_LEVEL: info immutable: true ``` ## What exactly is frozen The API server validation rejects any update request that changes `data`, `binaryData` (ConfigMap) or `data`/`stringData` (Secret) on an object where `immutable` is true. It also rejects flipping `immutable` from true back to false or removing the field — the transition is one-way on purpose, otherwise the guarantee would be worthless (you could unfreeze, edit, refreeze). What is *not* frozen: object metadata. Labels, annotations, ownerReferences and finalizers can still be updated, so garbage-collection and tooling annotations keep working. And the object can still be **deleted**. Immutable does not mean permanent — it means "the bytes under this name never change while this name exists". The practical consequence: `kubectl edit configmap app-config` and `kubectl patch` on the data will fail with a validation error such as `field is immutable when immutable is set`. `kubectl apply` fails the same way, because apply is an update. `kubectl replace --force` "works" only because it deletes and recreates the object, which is a different and much more disruptive operation — for a moment the object does not exist, and any Pod that starts in that window fails to mount it. ## Why teams want it — safety A mutable ConfigMap mounted as a volume is a live wire. Edit it and the kubelet will, within a minute or so, rewrite the files inside every Pod that mounts it, on every node, with no rollout, no version record and no rollback other than editing it back. Applications that read config once at startup see nothing; applications that re-read see a change nobody deployed. Environment-variable consumers see nothing until they happen to restart — which means a Pod rescheduled at 3 a.m. silently picks up a config nobody intended to ship. Immutability converts that into an explicit, versioned deployment: a new object name, a new Pod template, a rolling update you can watch, pause and roll back. Config becomes as reviewable as an image tag. ## Why teams want it — scale The kubelet has to keep mounted ConfigMap and Secret contents fresh. With the default change-detection strategy it opens a watch on each object that a Pod on that node references. Across a large cluster this can be tens of thousands of individual watches, all held open by the API server, all costing memory and CPU there. If an object can never change, watching it is pure waste. The kubelet knows the flag and simply fetches the object once and stops. This was the motivating use case for the feature (alpha in 1.19, GA in 1.21) and it is the reason large platforms adopt it broadly rather than for the safety argument alone. ## The cost you accept You trade in-place edit for delete-and-recreate. Every change now produces a new object, which means you need a naming scheme (content hash or explicit version suffix) and a story for cleaning up old objects, or you accumulate garbage in etcd. Tooling that expects to write in place — a controller that renews a TLS certificate into an existing Secret, an operator that syncs from an external secret store — breaks against immutable objects unless it is written to create new ones. Check those integrations before switching a namespace over. ## How it interacts with consumers A Pod referencing an immutable ConfigMap behaves identically to one referencing a mutable one, except that the mounted files will never change for the lifetime of that Pod. `optional: true` still applies for missing objects. Nothing in the Pod spec needs to know about the flag.

  • Can you turn immutability off again if you change your mind?
    No. The API server rejects any update that unsets or flips `immutable` back to false, precisely so the guarantee cannot be worked around. Your only escape is to delete the object and create a mutable one with the same name, which briefly leaves Pods unable to mount it and is disruptive on any node that starts a Pod in that window.
  • Does immutability change anything for a Pod that already mounts the object?
    Only that the mounted files and injected environment variables will never change for the life of that Pod. Mount mechanics, `optional: true` handling and startup failure behaviour when the object is missing are all identical to the mutable case.

It is the difference between editing a shared document in place and publishing a new numbered revision: same content change, but one of them leaves a trail and a rollback path.

saying these in an interview costs you the question

  • Claiming an immutable ConfigMap cannot be deleted — deletion is always allowed, only data updates are blocked.
  • Thinking you can set `immutable: false` later to make a quick fix.
  • Believing immutability encrypts or otherwise protects Secret contents — it is about change control, not confidentiality.
  • Saying labels and annotations are frozen too; only the data fields are.

context