envsubst — Substitute Environment Variables in Text
Practical guide to envsubst (GNU gettext): substitute environment variables in templates and text files — safely, without shell expansion.
envsubst is part of GNU gettext and replaces every $VAR and ${VAR} reference in a text with the value of the matching environment variable. Unlike eval or a shell, it performs no shell expansion – no command substitution, no globbing, no quoting tricks – it only swaps in variable values. That is exactly what makes it a safe tool for filling templates such as nginx configurations, .env files or Kubernetes manifests with values from the environment. Pass an argument like '$VAR1 $VAR2' to restrict substitution to specific variables, so other placeholders (for example nginx's own $uri) stay untouched. This guide walks you through the invocations you actually reach for, from Docker entrypoints to CI/CD pipelines.
Basic Usage
envsubst < <template> > <output> — Replace all $VAR and ${VAR} references with their values.
envsubst < config.template > config.confecho '$HOME' | envsubst — Substitute variables in piped text.
echo 'Hello $USER, your home is $HOME' | envsubstenvsubst < <template> — Output substituted content to stdout.
envsubst < nginx.conf.templatecat <template> | envsubst > <output> — Pipe template through envsubst.
cat docker-compose.yml.tmpl | envsubst > docker-compose.ymlRestrict Variables
envsubst '$VAR1 $VAR2' < <template> — Only substitute specific variables (leave others as-is).
envsubst '$DB_HOST $DB_PORT' < config.template > config.confenvsubst '${VAR1}' < <template> — Substitute only one specific variable.
envsubst '${APP_VERSION}' < version.txt.tmpl > version.txtenvsubst --variables '<shell-format>' — List all variable names referenced in the argument.
envsubst --variables "$(cat nginx.conf.template)"Docker & Container Usage
envsubst < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf — Template an NGINX config in a Docker entrypoint.
envsubst '${NGINX_HOST} ${NGINX_PORT}' < default.conf.template > /etc/nginx/conf.d/default.confenvsubst < app.env.template > .env — Generate a .env file from a template during deployment.
envsubst < app.env.template > .envenvsubst '$VAR' < template — Substitute only selected variables; all other ${...} references stay literal.
echo 'Home: $HOME, keep: ${BUILD_ID}' | envsubst '$HOME'CI/CD & Scripting
export VAR=value && envsubst < template > output — Set a variable and substitute in one command chain.
export VERSION=1.2.3 && envsubst < manifest.yml.tmpl > manifest.ymlVAR=value envsubst < template — Inline variable definition for the envsubst call.
APP_NAME=myapp envsubst < deploy.yaml.tmplenv $(cat .env | xargs) envsubst < template — Load variables from a .env file and substitute.
env $(cat .env | xargs) envsubst < config.template > config.confenvsubst < k8s/deployment.yaml.tmpl | kubectl apply -f - — Template a Kubernetes manifest and apply it directly.
export IMAGE_TAG=v2.0 && envsubst < k8s/deployment.yaml.tmpl | kubectl apply -f -Common Patterns
for f in *.tmpl; do envsubst < "$f" > "${f%.tmpl}"; done — Process all template files and drop the .tmpl extension.
for f in conf/*.tmpl; do envsubst < "$f" > "${f%.tmpl}"; doneenvsubst --variables "$(cat template)" | sort — List all variables a template requires.
envsubst --variables "$(cat nginx.conf.template)" | sortenvsubst < template | diff template - — Show what was substituted in a template.
envsubst < config.template | diff config.template - Conclusion
The strength of envsubst is its safe, tightly scoped substitution: it only swaps $VAR/${VAR} and, unlike eval or a shell, runs no commands at all – ideal for filling untrusted templates. When you pass a shell-format string such as '$DB_HOST $DB_PORT', envsubst restricts substitution to exactly those variables; every other placeholder (for example nginx's own $uri) is left verbatim. Watch out for one pitfall, though: an unset variable is silently replaced with an empty string rather than reported as an error – use envsubst --variables to check that every required value is present in the environment before you rely on the output. envsubst has no $$ escape for a literal dollar sign; to keep a reference verbatim, simply leave it out of the list of variables to substitute.
Further Reading
- GNU gettext: envsubst Invocation – official reference for invocation and options
- GNU gettext: The Programmer's View – manual for the full gettext package that envsubst is part of