compareupdated 2026-04-19

.env files vs Kubernetes Secrets & ConfigMaps

How .env files map to Kubernetes Secrets and ConfigMaps. When to split, when to combine, and how to avoid the classic base64-is-not-encryption trap.

TL;DR

  • .env — flat text file for local dev. No encryption. One process sees it.
  • ConfigMap — Kubernetes object for non-sensitive config. Shareable across pods, namespaces.
  • Secret — same shape as ConfigMap but base64-encoded and access-controlled via RBAC.
  • Base64 is not encryption. Secrets are not secrets at rest unless you enable encryption-at-rest.

The mental model

When you move from "my laptop" to "Kubernetes," your .env gets split in two:

  • Non-sensitive values (PORT, LOG_LEVEL, NODE_ENV, feature flags) → ConfigMap
  • Sensitive values (DATABASE_URL, JWT_SECRET, API_KEY) → Secret

Both become environment variables inside your pod. Your app reads them the exact same way it read .env process.env.DATABASE_URL works unchanged.

Mapping a .env to Kubernetes

# .env (local)
NODE_ENV=production
LOG_LEVEL=info
PORT=3000
DATABASE_URL=postgres://user:pass@db/app
JWT_SECRET=super-long-secret

Split into two Kubernetes objects:

# configmap.yaml — non-sensitive
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  NODE_ENV: production
  LOG_LEVEL: info
  PORT: "3000"
---
# secret.yaml — sensitive (base64-encoded)
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  DATABASE_URL: cG9zdGdyZXM6Ly91c2VyOnBhc3NAZGIvYXBw
  JWT_SECRET: c3VwZXItbG9uZy1zZWNyZXQ=

Mount both into your Deployment with envFrom::

spec:
  containers:
    - name: app
      envFrom:
        - configMapRef:
            name: app-config
        - secretRef:
            name: app-secrets

Our .env → Kubernetes converter does the base64 encoding and scaffolding for you — paste .env, pick "Kubernetes Secret", copy the YAML.

Base64 ≠ encryption

This is the single most misunderstood fact about Kubernetes Secrets. The base64 encoding exists because etcd needs valid UTF-8 bytes, not because Kubernetes is encrypting anything. Anyone with read access to the Secret object can decode the values with echo ... | base64 -d.

To get actual encryption at rest, you need one of:

  • Encryption-at-rest for etcd (native K8s feature, requires config)
  • Sealed Secrets (Bitnami controller — encrypts with a cluster-specific key so Secret YAML can be safely committed to git)
  • External Secrets Operator (pulls live from Doppler, Vault, AWS Secrets Manager, etc. — Secret objects never contain the actual values)

When to use which

StageUse
Local dev on your laptop.env
docker-compose.env + env_file:
Kubernetes — non-sensitiveConfigMap
Kubernetes — sensitiveSecret + encryption-at-rest enabled
Kubernetes — multi-cluster / multi-teamExternal Secrets Operator pointing at Doppler/Vault
Kubernetes — GitOps / ArgoCDSealed Secrets (encrypted YAML in git)

Common mistakes

  • Committing a Secret YAML to git. Base64 is not encryption. Anyone cloning the repo reads the values. Use Sealed Secrets if you want them in git.
  • Putting everything in Secrets "to be safe." Non-sensitive config in ConfigMaps is cheaper, clearer, and more auditable.
  • Mounting Secrets as files instead of env vars "for security." The filesystem mount is a read-only view into the same data — it's not more or less secure, just different ergonomics.
  • Forgetting to restart pods after updating a Secret. Kubernetes doesn't auto-reload env vars. You need a rollout restart or a sidecar that watches for changes.

Recommended production stack

For a mid-sized team running Kubernetes in 2026:

  1. Store secrets in Doppler or Infisical — see our comparison.
  2. Sync them into the cluster via External Secrets Operator. K8s Secret objects get auto-populated from the upstream.
  3. Use ConfigMaps for anything non-sensitive — environment name, feature flags, log levels.
  4. Enable etcd encryption-at-rest if self-hosting. Managed K8s (EKS, GKE, AKS) does this automatically.

Convert your .env in one click

If you're just migrating your first .env to Kubernetes, use the converter — paste the file, pick "Kubernetes Secret", copy the YAML. Good enough for dev clusters; for production, layer one of the solutions above.

Related guides

Related tools