A server list
The ~ markers keep the output tight, which is what makes it a usable config file
ips = ["10.0.0.1", "10.0.0.2"]
port = 8080
---
%{ for ip in ips ~}
server ${ip}:${port}
%{ endfor ~} Render a template exactly as templatefile would. Put the variables above a line of three dashes and the template below it.
Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.
The answer appears here
Paste on the left and press Render. Nothing leaves this tab.
Nothing else to flag.
No formatting problems, and nothing the rules object to. Worth remembering what that covers: this reads the file you pasted, not the account or cluster it will be applied to.
No finding matches that filter.
Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.
The ~ markers keep the output tight, which is what makes it a usable config file
ips = ["10.0.0.1", "10.0.0.2"]
port = 8080
---
%{ for ip in ips ~}
server ${ip}:${port}
%{ endfor ~}Terraform tries to resolve it and fails before the file is ever written
user = "app"
---
#!/bin/sh
export HOME=${HOME}
useradd ${user}Every iteration emits the directive's own newline as a blank line
names = ["a", "b"]
---
%{ for n in names }
- ${n}
%{ endfor }These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
A template's scope is exactly the map passed to templatefile. Variables and locals from the configuration do not exist inside it.
Instead:Pass what the template needs explicitly: templatefile(path, { name = var.name }).
Every ${ } in the script is read as a template expression, so the render fails on names that belong to the shell.
Instead:Write ${VAR} for anything the shell should expand, and pass only what Terraform should fill in.
The newline after the directive is emitted on every iteration, which puts a blank line between every entry and breaks any format that cares.
Instead:Write %{ for x in xs ~} and %{ endfor ~}.
Not your variables, not your locals, not your resources. That boundary is the first thing people hit when moving an inline string into a template file.
templatefile(path, vars) gives the template vars and nothing else. A template referring to var.something or local.something fails, because neither exists in there. Everything the template needs has to be listed in the map, which is tedious and is what makes a template reusable.
${HOME} means one thing to a shell and another to Terraform, which tries to resolve it as a template variable and fails before the file is written. This is the commonest failure in a user_data script or a Docker Compose file. Escape it as $${HOME} to pass the literal through.
%{ for x in xs } leaves the newline after the directive in the output, so a generated config gets a blank line between every entry, and a JSON document gets a syntax error. %{ for x in xs ~} removes the directive's own line. This is the difference between a template that works and one that nearly does.
if, else, else if, endif, for and endfor. There is no while, no include and no nesting of templates. A misspelling is reported as an unknown directive, which is at least clear.
The convention is .tftpl, and Terraform does not care. Naming it .tpl or .sh.tftpl is fine; what matters is that the path resolves from the module, which is why ${path.module}/ is almost always in front of it.
The file on disk, because there is no disk here. Paste the template text instead. Everything renders in your browser and nothing is uploaded, so a template holding real values is safe to test.