Variable templating lets one secret reference another using ${VAR} syntax, so you can compose values instead of repeating them. The dotEnv CLI resolves these references locally when you ask it to, which keeps your stored secrets DRY and your generated .env files fully expanded.
Basic interpolation
Reference another variable with ${NAME} or the bare $NAME form. Resolution is recursive, so a reference can itself contain references:
Resolve on pull
By default the CLI leaves references intact. Pass --resolve (or -r) to expand them during a pull or export:
With --resolve, the secrets above expand to:
Defaults and conditional values
Beyond plain substitution, the interpolator understands three shell-style operators inside the braces:
| Syntax | Meaning |
|---|---|
| ${VAR:-default} | Use VAR if it is set, otherwise fall back to default. |
| ${VAR:+alt} | Use alt if VAR is set, otherwise an empty string. |
| ${VAR:?message} | Fail with message if VAR is not set. |
The operand of an operator can itself reference other variables, so defaults can be composed too.
Unresolved and missing variables
If a referenced variable is not set, the CLI keeps the original ${VAR} text in the output rather than emitting an empty value, so nothing silently disappears. The :? operator is the way to turn a missing required value into a hard error instead.
Circular references
The interpolator detects cycles. If two variables reference each other, resolution stops with a clear "circular reference detected" error rather than looping forever:
When to resolve
Keep references unresolved in storage so a change to HOST automatically flows into BASE_URL everywhere. Resolve only at the point of consumption (when you pull or export the final .env for a deploy) by adding --resolve. Combine this with Environment Inheritance to share a base value across levels and reference it from each.