← Back

2026

Kubernetes ConfigMaps: Configuration That Lives in the Cluster

Applications need configuration. ConfigMaps are how Kubernetes separates that configuration from the container image, making it possible to deploy the same image across environments with different settings. Here is how they work and where they fit.

Every application needs configuration. Which database to connect to, which port to listen on, which feature flags are active, how verbose the logging should be. These are the kinds of settings that change between environments and change over time, which means they do not belong baked into a container image.

Before Kubernetes, you would typically pass configuration through environment variables set in a shell script, a dotenv file checked into a repository somewhere, or a config file that varied between servers. In Kubernetes the answer is a ConfigMap. It is a first-class object in the cluster that holds key-value pairs and it separates configuration from the application code and container image that runs it.

The idea is straightforward: define your configuration once in a ConfigMap, then reference it from your pods. Change the ConfigMap and you change the configuration without touching the application or rebuilding an image. It sounds simple and mostly it is, but there are a few details worth understanding before you start leaning on them heavily.

What a ConfigMap actually is

A ConfigMap stores data as a collection of key-value pairs. The values can be short strings like a hostname or a port number. They can also be entire file contents, which is how you represent a full configuration file in YAML or INI format as a ConfigMap entry. There is no schema enforcement. Kubernetes does not know or care what format your values are in. It stores them as strings and hands them to your pods in whatever form you request.

The data field holds UTF-8 string values. The binaryData field exists for base64-encoded binary content, though this is rarely useful in practice. Most configuration is plain text. The object lives in a namespace, so it is only accessible to pods in the same namespace unless you explicitly reference it from somewhere else.

A ConfigMap for an application

apiVersion: v1

kind: ConfigMap

metadata:

name: app-config

namespace: production

data:

APP_ENV: "production"

LOG_LEVEL: "warn"

DB_HOST: "postgres.production.svc.cluster.local"

DB_PORT: "5432"

config.yaml: |

server:

port: 8080

timeout: 30s

cache:

ttl: 300

The config.yaml key above holds a full YAML file as its value. When this ConfigMap is mounted as a volume, that key becomes a file named config.yaml inside the container, with the multiline content intact.

How pods consume ConfigMaps

There are a few ways to get ConfigMap data into a running container. The right choice depends on how the application reads its configuration.

Environment variables

You can project individual keys from a ConfigMap directly into a container as environment variables. Each variable gets its own name in the container's environment, mapped from a key in the ConfigMap. The container sees them as ordinary env vars. This is simple to set up but has one practical consequence: if the ConfigMap changes, the container does not see the new value until it restarts. The environment is only read at container startup.

Mounted volumes

Mounting a ConfigMap as a volume creates files inside the container. Each key in the ConfigMap becomes a filename and its value becomes the file content. This is particularly useful for configuration files that an application reads from disk. Unlike environment variables, mounted ConfigMaps do update inside a running container when the source ConfigMap changes, though there is a short delay while the kubelet syncs the new content.

envFrom

The envFrom field pulls all keys from a ConfigMap into the container environment at once. Rather than naming each key individually, you point at the whole ConfigMap. Every key becomes an environment variable. This is convenient when a ConfigMap holds a cohesive set of settings, but it can also silently inject more variables than you expect if the ConfigMap grows over time.

Command arguments

You can reference environment variables populated from a ConfigMap in a container's command or args fields. The variable is expanded when the container starts. This lets you pass configuration into an application that reads its settings from command line arguments rather than a config file or the environment directly.

What this looks like in a pod spec

The two most common patterns are projecting individual keys as environment variables and mounting the entire ConfigMap as a directory of files. Here is what both look like side by side.

Environment variable from a specific key

spec:

containers:

- name: app

image: myapp:latest

env:

- name: LOG_LEVEL

valueFrom:

configMapKeyRef:

name: app-config

key: LOG_LEVEL

Volume mount — ConfigMap as files

spec:

volumes:

- name: config-vol

configMap:

name: app-config

containers:

- name: app

image: myapp:latest

volumeMounts:

- name: config-vol

mountPath: /etc/config

readOnly: true

With the volume mount above, the container will have a file at/etc/config/config.yaml containing the YAML block from the ConfigMap. It will also have files for every other key. If you only want specific keys rather than the whole ConfigMap, the items field under configMap lets you list exactly which keys to project and what filenames to give them.

Immutable ConfigMaps

ConfigMaps support an immutable field. Setting it to true tells Kubernetes that the ConfigMap will never be updated. Once set, any attempt to change the data will be rejected. The only way to change the configuration is to create a new ConfigMap with a new name and update the pod spec to reference it.

Worth noting

Immutability is not just a safety feature. When a ConfigMap is immutable, the kubelet stops watching it for changes. In clusters with hundreds of pods all mounting the same ConfigMap, each of those pods normally maintains a watch connection to the API server so it can receive updates. Marking the ConfigMap as immutable eliminates all of those watches at once. For ConfigMaps that genuinely never change after deployment, this is a straightforward performance improvement that costs nothing to apply.

Immutable ConfigMap

apiVersion: v1

kind: ConfigMap

metadata:

name: app-config-v3

namespace: production

immutable: true

data:

APP_ENV: "production"

LOG_LEVEL: "warn"

Things that go wrong

ConfigMaps are easy to misuse in a few consistent ways. These are the ones that come up most often.

Storing secrets in ConfigMaps

ConfigMap data is stored in etcd without encryption. Anyone with read access to the namespace can retrieve a ConfigMap and see its contents. Putting database passwords, API tokens or private keys in a ConfigMap is a mistake that is easy to make and easy to miss in a code review. Secrets exist for exactly this reason. Even if Secrets are not encrypted at rest by default in all cluster configurations, they signal intent, can be restricted with RBAC and work with external secret management systems. ConfigMaps should hold non-sensitive data only.

Large binary data in ConfigMaps

ConfigMaps have a size limit of one megabyte per object. That limit is set by etcd, which stores all Kubernetes objects. Trying to embed large files, bundled assets or anything that approaches that ceiling causes unexpected failures at apply time. The appropriate place for large data is a PersistentVolume or an external storage system. ConfigMaps are for configuration, not for general file storage.

Missing immutable flag on frequently read ConfigMaps

Every time a ConfigMap changes, the kubelet has to detect the change and sync it to any pods that mount it as a volume. In clusters with many pods watching the same ConfigMap, this creates a steady stream of watch events against the API server. Setting immutable to true on a ConfigMap tells Kubernetes that the object will never change. The kubelet stops watching it. This is a small change that meaningfully reduces API server load when ConfigMaps are used at scale.

Expecting instant updates in environment variables

A common source of confusion is changing a ConfigMap and assuming running pods will reflect the change straight away. For mounted volumes there is a delay, but the update does eventually arrive without a restart. For environment variables there is no automatic update at all. The container sees the values that were present at startup and nothing changes until the pod is recreated. Applications that need to pick up configuration changes at runtime are better served by volume mounts than by environment variables.

Where it fits

ConfigMaps solve the problem of configuration that belongs to the cluster rather than the image. An application image should be built once and deployed anywhere. ConfigMaps are how you give that image different settings in different environments without rebuilding it. The image knows how to read configuration. The ConfigMap provides what that configuration should say.

In the broader Kubernetes object model, ConfigMaps sit alongside Secrets as the two standard mechanisms for injecting external data into pods. Secrets handle sensitive values. ConfigMaps handle everything else. The split is intentional: it keeps the access controls, audit trails and encryption concerns for sensitive data separate from the ordinary configuration that any developer in the team can read freely.

ConfigMaps also show up in a less obvious context: many Kubernetes components use them internally to store state. The scheduler stores leader election information in a ConfigMap. Various operators use ConfigMaps as lightweight coordination mechanisms. Once you start looking for them, you find them throughout the system. Understanding how they work gives you a clearer picture of how Kubernetes itself manages persistent configuration data across its own components.