pass environment variable when use kubectl apply -f file.yaml
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
kubectl apply -f file.yaml does not expand shell variables inside YAML by itself. If you want one manifest to behave differently across environments, you need a preprocessing step or a proper templating tool. The right choice depends on how much substitution logic you need and how much safety you want around missing values.
Why kubectl apply Does Not Expand Variables
Kubernetes manifests are plain YAML files. kubectl reads them as data, not as shell scripts, so a value like $IMAGE_TAG is not expanded automatically.
If you run:
then kubectl apply -f deployment.yaml will send the literal string my-app:$IMAGE_TAG unless you substitute it first.
Use envsubst for Simple Substitution
For straightforward shell-variable replacement, envsubst is the simplest approach.
Example manifest:
This works well when your needs are limited to direct string substitution.
Restrict Which Variables Are Expanded
Blind substitution can be risky in larger files. You can restrict envsubst to specific variables:
This avoids unexpected replacements when other $NAME strings appear in the file.
Fail Fast on Missing Variables
One weakness of plain envsubst is that unset variables become empty strings. Add checks before rendering:
This prevents deploying broken manifests like image: my-app:.
Use kubectl create configmap and secret When Values Belong in Kubernetes
If the goal is to inject runtime environment variables into pods, do not always bake them into templated YAML. Often it is better to store them in a ConfigMap or Secret.
Then reference it from the pod spec:
This keeps deployment logic and runtime configuration separate.
When to Use Helm or Kustomize Instead
If your manifests need conditionals, loops, overlays, or environment-specific patches, stop relying on shell substitution and use proper tooling.
Helm is better when:
- You need reusable packaged templates.
- You need values files per environment.
Kustomize is better when:
- You want base manifests plus small overlays.
- You want native
kubectlcompatibility.
Shell substitution is fine for simple pipelines, but it does not scale cleanly to complex deployment logic.
CI Usage Pattern
In CI, keep substitution explicit and visible in logs without printing secrets.
For sensitive values, prefer Kubernetes Secret resources and secret-management tooling rather than direct shell expansion into manifests.
Common Pitfalls
- Expecting
kubectl applyto expand$VARautomatically. - Using
envsubstwithout checking required variables first. - Substituting secrets directly into logs or build output.
- Using shell substitution for configuration that really belongs in
ConfigMaporSecret. - Stretching simple substitution too far when Helm or Kustomize would be clearer.
Summary
- '
kubectl apply -fdoes not perform shell-variable expansion.' - '
envsubstis the simplest way to substitute environment variables before apply.' - Restrict expanded variables and fail fast on missing required values.
- Use
ConfigMapandSecretfor runtime configuration instead of forcing everything into templates. - Move to Helm or Kustomize when manifest logic becomes more than simple substitution.
Related reading
- Pass multiple variables in helm template
- Pass postgres parameter into Kubernetes deployment
- Pass statefulset's replica count to it's pod
- Passing JVM args to Docker image of Spring boot app on Kubernetes
- Passing long configuration file to Kubernetes
- Passing separate env variables to statefulset pods
- PersistentVolume does not use local host path
- PersistentVolumeClaim is stuck ''waiting for a volume to be created, either by external provisioner ebs.csi.aws.com'' on new AWS EKS cluster

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.