In short
You want the same image in dev and prod, just with a different database URL and log level. ConfigMaps and Secrets hold those settings outside the image, so one build runs everywhere.
ConfigMaps store non-sensitive configuration data, Secrets store sensitive values (base64-encoded, not truly encrypted by default) — both let you decouple configuration from your container images.

Think of it like this
Notice board vs sealed envelope
The hostel mess menu goes on the notice board; anyone can read it. The warden's locker code goes in a sealed envelope, handed only to who needs it. ConfigMaps are the notice board. Secrets are the envelope, but you still have to guard it.
Watch it happen
Which one should hold this value?
ConfigMap
- LOG_LEVEL, feature flags, URLs
- Stored as plain text
- Fine to keep in Git
Secret
- Passwords, API keys, TLS certs
- Only base64-encoded by default
- Restrict with RBAC, encrypt at rest
If leaking the value would hurt, it's a Secret, and it still needs RBAC, encryption at rest and ideally an external secrets manager.
The big ideas
What you need to know
Config outside the image
Build the image once. Inject settings per environment, so dev and prod run the exact same tested artefact.
base64 is not encryption
Anyone who can read a Secret can decode it in one command. Lock down who can get secrets with RBAC.
Env vars or files
Load values as environment variables, or mount them as files. Mounted files update without a restart, env vars don't.
External stores scale better
Many teams sync secrets from Vault or a cloud secrets manager instead of keeping them in YAML at all.
See it in code
Walk through the code
1apiVersion: v12kind: ConfigMap3metadata: { name: app-config }4data:5 LOG_LEVEL: "info"6---7apiVersion: v18kind: Pod9metadata: { name: api }10spec:11 containers:12 - name: api13 image: myapi:114 envFrom:15 - configMapRef: { name: app-config }16 - secretRef: { name: db-creds }1/3A ConfigMap with non-sensitive settings, safe to commit alongside your manifests.
Create the Secret from the command line so it never sits in Git: kubectl create secret generic db-creds --from-literal=DB_PASSWORD=devpass
Save yourself the pain
Common mistakes
Oops
Committing a Secret YAML with base64 values to a public repo, thinking it's encrypted.
Do this instead
Treat base64 as plain text. Create secrets from the CLI, or use Sealed Secrets or External Secrets to keep Git safe.
Oops
Updating a ConfigMap and expecting env vars in running pods to change.
Do this instead
Env vars are read at start-up. Restart with kubectl rollout restart deploy/api, or mount the config as files instead.
Your mission
One image, two configs
Quick check
What protects a Kubernetes Secret by default?
Go deeper
- 1Create a ConfigMap and mount it as environment variables in a Pod.
- 2Create a Secret and reference it in a Deployment, and note it's only base64-encoded, not encrypted.
- 3Learn why a real production setup often pairs Secrets with a dedicated secrets manager (Phase 12) for actual encryption.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.