Terraform templatefile Tester

Render a template exactly as templatefile would. Put the variables above a line of three dashes and the template below it.

Paste below, or drop a file anywhere on this panel

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.

Examples

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.

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 ~}

A shell variable in a script

Terraform tries to resolve it and fails before the file is ever written

user = "app"
---
#!/bin/sh
export HOME=${HOME}
useradd ${user}

A for with no trim markers

Every iteration emits the directive's own newline as a blank line

names = ["a", "b"]
---
%{ for n in names }
- ${n}
%{ endfor }

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Referring to var.something inside a template

    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 }).

  2. Putting a shell script in a template without escaping

    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.

  3. Omitting the ~ on a for directive

    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 ~}.

A template sees only the map you pass it

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.

The scope is exactly the second argument

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.

Shell syntax collides with interpolation

${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.

The ~ markers decide whether the output has blank lines

%{ 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.

The directives are a short list

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.

A template file has no required extension

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.

What this cannot see

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.

More terraform tools

Terraform Validator & Formatter Does it parse, and is it formatted? Terraform dynamic Block Generator It is ingress.value, not each.value Terraform check and precondition Generator A failed check does not stop the apply Terraform variables.tf Generator From the var. references you already wrote Terraform Unused Declaration Linter Dead variables, locals and data sources Terraform Atlantis YAML Generator when_modified misses your modules Terraform Function Tester and HCL Console terraform console, in a tab Terraform for Expression Tester Where do the keys collide? Terraform Interpolation Tester null becomes an empty string Terraform Resource Count Calculator How many objects, not how many blocks Terraform count to for_each Converter With the moved blocks it needs Terraform moved Block Generator Rename without destroying Terraform state mv Command Builder No plan, no undo Terraform target Flag Builder And why to stop using it Terraform outputs.tf Generator Outputs are not sensitive by default Terraform Remote State Data Source Generator It grants read of the whole state Terraform Provider Block Generator docker is not hashicorp/docker Terraform .gitignore Generator and Checker .terraform* eats the lock file Terraform to OpenTofu Migration Checker The state is the part to watch Terraform tfvars to JSON Converter The JSON file wins Terraform Version Constraint Parser What ~> actually allows Terraform Resource Address Parser Quote it before the shell eats it Terraform cidrsubnet Calculator newbits is added, not the target Terraform Import Block Generator The id is not the name Terraform Lock File Viewer Why CI fails and your laptop does not Terraform Variables Checker A missing value hangs CI Terraform tfvars to Env Vars Converter Lists and maps have to be JSON Terraform Deprecated Syntax Checker What a current Terraform rejects Terraform State File Viewer Read it without uploading it Terraform Plan JSON Viewer It is not redacted Terraform HCL to JSON Converter And what the conversion loses Terraform Module Source Validator version only works for the registry Terraform Backend Config Decoder Is state actually locked? Terraform Naming Convention Validator A hyphen makes a resource unreferenceable

Elsewhere on the site