Templates
Loom uses Go's text/template syntax. Inside any templatable string, you can reference parameters with {{ .paramName }}.
Functions
| Function | Example | Result |
|---|---|---|
| Parameter access | {{ .serviceName }} | payments |
| Default value | {{ default "prod" .env }} | prod if .env is empty |
| Uppercase | {{ upper .serviceName }} | PAYMENTS |
| Lowercase | {{ lower .serviceName }} | payments |
| Indent | {{ indent 2 .config }} | Every line prefixed with 2 spaces |
| Newline + indent | {{ nindent 4 .config }} | Leading newline, then every line indented 4 spaces |
| Quote | {{ quote .value }} | "payments" (escaped double-quoted string) |
| To YAML | {{ toYaml .value }} | Value marshaled as 2-space-indented YAML |
| From YAML | {{ fromYaml .items }} | String parsed into a value (list, map, or scalar) |
| Split | {{ .regions | split "," }} | String divided around a separator, empty elements dropped |
Multi-line Values
Go templates substitute text literally, so inserting a multi-line parameter into an indented YAML block would leave its continuation lines at column 0. Use nindent to re-indent the whole value:
data:
app-config: |{{ .appConfig | nindent 4 }}With appConfig set to key1: val1\nkey2: val2, this renders:
data:
app-config: |
key1: val1
key2: val2Note the | sits directly against the template expression — nindent supplies the newline.
List Parameters
Parameters are always strings, but a string can contain YAML. fromYaml parses it into a real value so templates can range over it or re-serialize it.
Range over a list parameter (works with flow style like regions: "[us-east-1, eu-west-1]" or a block scalar):
regions:
{{- range .regions | fromYaml }}
- {{ . }}
{{- end }}Or merge a list parameter into an existing list by round-tripping through toYaml, which validates and re-indents the fragment:
env:
- name: LOG_LEVEL
value: info
{{- .extraEnv | fromYaml | toYaml | nindent 2 }}Malformed YAML in the parameter fails at render time instead of producing a broken file.
For simple comma-separated values, split avoids YAML syntax in the parameter entirely (with regions: "us-east-1,eu-west-1"):
regions:
{{- range .regions | split "," }}
- {{ . }}
{{- end }}split drops empty elements, so an empty parameter or a trailing separator yields no blank list items.
Where Templates Work
Templates are evaluated in:
- File contents (
newFiles) - File and folder paths (
newFiles) -- see Path Templating - Shell commands
- Commit messages
- PR/MR titles and bodies
- Feature branch names
- Child module parameters
- Dynamic param commands
Path Templating
File and folder names are rendered as Go templates, just like file contents. You can use {{ .paramName }} directly in file and directory names.
| Source path | With serviceName=payments, env=prod | Result |
|---|---|---|
{{ .env }}/config.yaml | prod/config.yaml | |
application-{{ .serviceName }}.yaml | application-payments.yaml | |
{{ .env }}/{{ .serviceName }}-deploy.yaml | prod/payments-deploy.yaml |
This means your module directory can look like:
onboard-service/
├── loom.yaml
├── {{ .env }}/
│ └── {{ .serviceName }}-app.yaml
└── shared/
└── config.yamlRunning with -p serviceName=payments -p env=prod produces:
prod/
└── payments-app.yaml
shared/
└── config.yamlDouble-Underscore Syntax
For convenience, Loom also supports a filesystem-friendly __paramName__ placeholder syntax. This is useful when your filesystem, shell, or editor has trouble with curly braces in filenames. Loom converts __paramName__ to {{ .paramName }} before rendering. Both syntaxes can be mixed freely.
__paramName__ syntax | Equivalent Go template |
|---|---|
__env__/config.yaml | {{ .env }}/config.yaml |
application-__serviceName__.yaml | application-{{ .serviceName }}.yaml |