

A Terraform string is just a sequence of characters, but almost everything you write in HCL touches one: resource names, tags, file paths, generated policies, connection strings. Knowing how Terraform builds, combines, and templates strings will save you from some of the more confusing errors you'll hit in a growing configuration.
This guide covers how strings are defined, how interpolation and template directives work, the two multiline syntaxes, and where to go for a deeper look at specific built-in functions.
What is a string in Terraform?
Terraform gives you two ways to write a string literal:
- Quoted strings – text wrapped in double quotes, e.g.
"us-east-1" - Heredoc strings – a multiline block bounded by a marker of your choosing, covered below
Quoted strings support a set of backslash escape sequences:
Two additional escapes don't use a backslash at all, and matter once you start interpolating: $${ produces a literal ${ instead of starting an interpolation, and %%{ produces a literal %{ instead of starting a directive. You'll want the first one any time a string needs to contain a literal dollar-brace sequence, for example when generating a shell script that itself uses variable expansion.
String interpolation in Terraform
Interpolation is how you drop a dynamic value into a string using ${ ... }. Terraform evaluates whatever is between the braces and converts it to a string if needed.
The expression inside ${ } can be a variable reference, an attribute reference, a function call, or a simple arithmetic expression:
If you need a literal ${var.name} in your output, rather than an interpolation, escape it with an extra dollar sign: $${var.name}.
env zero note: env zero's Environment Outputs feature borrows this same pattern to reference a value from a different environment: ${env0::}. Add a variable of type Environment Output, point it at another environment's output name, and env zero resolves the value at run time, no manual copy-paste or API calls between environments required. Right now only string-type outputs are supported, which lines up neatly with everything else in this guide, if the value you need is a list or map, you'll need to reference it a different way.Template directives: conditionals and loops inside a string
Interpolation isn't the only template sequence Terraform supports. A %{ ... } sequence is a directive, and it lets you branch or iterate inside a string, something most string-focused guides skip entirely.
The if / else / endif directive chooses between two outputs based on a boolean expression:
The for / endfor directive iterates over a list or map and concatenates the result of a template for each element. This is commonly used inside a heredoc to build a multiline block from a list variable:
The ~ immediately after for and before endfor is a whitespace strip marker. Without it, each directive line leaves behind its own newline and you end up with blank lines between entries. With it, only the newline that belongs to the generated content (the server ... line) survives.
Multiline strings in Terraform
For anything longer than a single line, Terraform uses heredoc syntax: an opening marker (<< or <<-, plus an identifier you choose), the content, and that same identifier alone on its own closing line.
Skip the heredoc for JSON and YAML. It's tempting to hand-write a JSON policy like the one above inside a heredoc, but a single missing comma will fail at apply time with a confusing error. Use jsonencode() or yamlencode() instead, and let Terraform guarantee valid syntax:
Indented heredocs
A standard heredoc treats every space as literal, which forces the closing marker (and every line of content) flush to the left margin, awkward when the block sits inside a nested resource. Add a hyphen, <<-EOT, and Terraform finds the line with the smallest number of leading spaces, then trims that many spaces from every line:
That produces a string with no leading indentation on the first and third lines, and the second line's extra two spaces preserved relative to the others, letting you indent the whole block to match your code without indenting the actual output.
One more difference from quoted strings: backslash characters inside a heredoc are not treated as escape sequences, they're literal. The only two special sequences that still work are $${ and %%{.
Terraform string functions
HCL ships a full library of built-in string functions. Here are the ones you'll reach for most:
FunctionWhat it doesformat()Printf-style templating, e.g. format("%s-%02d", "web", 3)join() / split()Combine a list into a string, or divide a string into a listreplace()Substring find-and-replaceregex() / regexall()Pattern matching and extractionupper() / lower()Case conversiontrim() / trimspace() / trimprefix() / trimsuffix()Strip characters or whitespace from a stringsubstr()Extract part of a string by offset and lengthstartswith() / endswith() / strcontains()Boolean checks on string contentbase64encode() / base64decode()Base64 conversion, common for cloud-init user datatostring()Explicit conversion to string type
A couple of these in practice, building a consistent, lowercase resource name and cleaning up a variable that might carry stray whitespace:
For the full function-by-function reference across every category, not just strings, see env zero's Terraform Functions Guide and Terraform Map Variable guide for the collection-type equivalents like merge() and optional(). And if split() and join() are what brought you here, they get a full treatment, syntax, alternatives, and worked examples, in Terraform Split and Join Functions: Examples and Best Practices.
How to concatenate strings in Terraform
Three ways to combine strings, and when each one fits:
- Interpolation (
${}) – simplest option for combining a small, fixed number of values:"${var.first}-${var.second}" join()– the right choice when you're combining a list of unknown length, e.g. all the subnet IDs in a VPCformat()– best when you need precise control over layout, padding, or multiple substitutions in a fixed template
If you're splitting a delimited string apart specifically so you can loop over the pieces, pair split() with for_each, a common combination for turning one input variable into several resources.
Managing Terraform strings with env zero
Most of what goes wrong with Terraform strings in a team setting isn't the syntax, it's keeping values consistent, secret, and correctly typed across environments. env zero's variable management is built around that:
- String is the default variable type. Plain text is the most common Terraform Variable value type in env zero, and clicking Load Variables From Code pulls your string-type input variables straight from your
.tffiles at their default values. Complex types (lists, maps, objects) are supported too, entered as HCL or JSON. - Sensitive values stay masked. Rather than interpolating a credential or token directly into a string in your configuration, mark the variable as sensitive. Its value is masked in the UI after saving, so secrets don't end up sitting in plain text where anyone with template access can read them.
- Environment Outputs use string interpolation to cross environment boundaries. As noted above,
${env0::}lets one environment consume another's output value, string outputs only, for now. - Watch your quoting when setting variables via
TF_VAR_*. If you're passing a list or map value through an environment variable instead of the UI, env zero needs a properly formatted string, e.g.export TF_VAR_myvar='["a","b"]', and a missingtypefield on the variable is a common cause of format errors. See Handling Common Errors for the full breakdown.
Key points
Terraform strings can be written as quoted literals or heredocs, and both support ${} interpolation for dropping in dynamic values. Heredocs add multiline support, with an indented <<- variant for keeping code readable, and %{} directives add conditionals and loops that most references skip over. Built-in functions cover everything from case conversion to regex extraction, and env zero's variable management extends the same interpolation pattern across environments, without you needing to hardcode a secret to do it.
Frequently Asked Questions
Q. What is a string in Terraform?
A sequence of characters used to represent text, defined either as a quoted literal in double quotes or as a heredoc for multiline content. Both support interpolation.
Q. What's the difference between a quoted string and a heredoc?
Quoted strings are single-line and support backslash escape sequences like \n and \t. Heredocs span multiple lines, don't process backslash escapes, and are better suited to longer blocks like policy documents or config files.
Q. Can I use an if-statement inside a Terraform string?
Yes, using a %{ if } / %{ else } / %{ endif } directive inside a quoted or heredoc string. It's a template directive, distinct from interpolation, and works alongside a %{ for } directive for loops.
Q. How do I stop a heredoc from picking up unwanted indentation?
Use the indented form, <<-EOT instead of <. Terraform trims the smallest common leading whitespace from every line.
Q. Should I build a JSON string with a heredoc?
Generally no. Use jsonencode() (or yamlencode() for YAML) so Terraform validates the structure for you instead of relying on hand-typed brackets and commas.
Q. How do I concatenate strings in Terraform?
Use ${} interpolation for a small fixed number of values, join() for a list of unknown length, or format() when you need precise control over the output layout.
.webp)


