!exec
The !exec Atmos YAML function is used to execute shell scripts and assign
the results to the sections in Atmos stack manifests.
Availability and evaluation
Supported locations:
- CLI configuration (
atmos.yaml,atmos.d, and profiles): during configuration loading. - Resolved stack values: after inheritance, merging, and component template processing.
- Workflow prompt fields:
default,prompt,placeholder, andoptionswhere supported by theinput,confirm,choose,filter,file, andwritestep types, before the step executes.
Automatic evaluation requires native YAML tags from edition 2026-10-20, including unpinned projects. Quoted function strings remain literal; earlier editions retain legacy string-form behavior.
See YAML function scope for field restrictions, import timing, and native tags versus quoted strings.
Usage
var1: !exec echo 42
var2: !exec get-data.sh
var3: !exec atmos terraform output <component> -s <stack> --skip-init -- -json test_label_id
var4: !exec atmos terraform output <component> -s {{ .stack }} --skip-init -- -json test_map
var5: !exec atmos terraform output <component> -s {{ .stack }} --skip-init -- -json test_list
var6: |
!exec
foo=0
for i in 1 2 3; do
foo+=$i
done
echo $foo
You can execute inline shell scripts, scripts defined in external files, or even Atmos or Terraform commands
(e.g. !exec atmos terraform output).
!exec atmos terraform output is just as examples to show that you can get the outputs of an Atmos component using
the !exec YAML function, but it's not recommended to use.
Instead, use the !terraform.output
YAML function. It produces the same results, correctly handles complex types (lists and maps),
has a much simpler syntax, and automatically caches the results for the same component and stack (so if you are calling
it many times on the same component in the same stack, it will execute terraform output only once and the stack
processing will be much faster)
The result of a script execution can be a simple type (string, number, or boolean), in which case Atmos assigns it without modification.
If the result is a complex type (list, map or object), the script must return it as a JSON-encoded string. After receiving the JSON-encoded string, Atmos automatically decodes it into the corresponding YAML complex type.
Atmos uses the interp Go package to execute the shell scripts
in the !exec YAML function.
Package interp implements an interpreter that executes shell programs.
It aims to support POSIX and to behave like Bash, but it does not support all of its features.
You can use Atmos Stack Manifest Templating in the !exec YAML function expressions.
In stack component values, Atmos processes templates before executing the !exec function, allowing you to provide the parameters to
the function dynamically.
Concurrent execution
Configure settings.functions.exec.max_concurrency in
atmos.yaml to allow multiple ordinary !exec expressions in a document to run concurrently:
settings:
functions:
exec:
max_concurrency: 4
Your stack entries stay unchanged:
vars:
network: !exec ./lookup-network
cluster: !exec ./lookup-cluster
registry: !exec ./lookup-registry
The limit defaults to 1 for serial execution and must be a positive integer. With a higher limit, calls can
finish in any order; results retain their original YAML locations and types. Atmos does not detect shell
side-effect dependencies. Users enabling concurrency are responsible for coordinating shared files and other
external state. Skipped !exec expressions remain unexecuted.
Commands inherit Atmos standard input. Concurrent commands share that input stream; input is not broadcast
to every command, and which command reads each part is not guaranteed. Coordinate commands that read stdin,
or set the limit to 1 when they must read serially.
Atmos supports type-aware merging of YAML functions and concrete values, allowing them to coexist in the inheritance chain without type conflicts. See the full explanation: YAML Function Merging