Terraform contains
What is the Terraform contains function?
Terraform's contains(list, value) function returns true if the specified value exists in the given list, tuple, or set, and false if it does not. It uses the same equality logic as the == operator, so a match has to be exact. Case, type, and whitespace all count.
Basic Terraform contains syntax
The Terraform contains function takes two arguments:
- The collection to search, which has to be a list, tuple, or set.
- The value you are checking for.
A valid call looks like this.
Pass a map as the first argument, and Terraform throws an error because contains has no concept of keys.
If your data is structured as a map and you want to check whether a value exists within it, you need the map's values rather than its keys, which usually means wrapping it in values() first.
Terraform will raise a flag if you skip that step, so it is worth checking your data structure before you assume contains will work on it directly.
What Terraform contains actually does
Run this in the Terraform console, and you will get true.
Change the value to something outside the list, and the function returns false instead.
The contains function does not partially match, does not coerce types for you, and does not care where in the list the value sits, only that at least one element matches or not.
Terraform's definition of == requires the same type and the same value, so contains(["1", "2", "3"], 1) returns false, not an error: the list holds strings, and the value passed in is a number.
An example of Terraform contains in action
The most common use of contains is variable validation. You often need to match a virtual machine (VM) size or specific Azure region to one of a short list of approved values before Terraform lets a plan run.
You also use contains during conditional resource creation. Combine contains with count or for_each to control whether a resource gets created at all, based on whether an element is present in a list.
That ternary turns the boolean that contains returns into a conditional expression Terraform can use directly in count, with no separate local required.
Locals benefit from the same logic. Wrapping a contains check in a local gives you conditional logic based on membership that you can reuse across a configuration without repeating the check in every resource block.
Common mistakes users make with Terraform contains
As Terraform's error message does not always make clear that contains wants a list, tuple, or set rather than a map, a common mistake is passing a map as the first argument.
Type mismatches between the value and the list elements also cause problems. Comparing a number to a string feels like it should work, but 1 and "1" are not equal in Terraform, so a contains check on a list of numbers can silently return false against a string value in a way that makes the issue difficult to spot in a Terraform plan output.
A third mistake people often make is not realizing that contains is case sensitive when it comes to strings, so contains(["Prod"], "prod") returns false even though the values look like an obvious match to a human reading the configuration.
A related mistake shows up once contains gets folded into a bigger conditional. A count argument can break on contains(local.vlist, "abc") ? 1 : 0 || contains(local.vlist, "def") ? 1 : 0, chaining two ternaries with || into an invalid expression. Parenthesizing each membership check and combining them first fixes it, with contains staying exactly as it was: (contains(local.vlist, "abc") || contains(local.vlist, "def")) ? 1 : 0.
Test with Terraform console before wiring a contains check into validation logic or resource conditionals to catch most of this early, especially as it costs nothing.
The nearest alternatives to Terraform contains
contains has two close neighbors in Terraform syntax: strcontains, which sounds like a synonym but works on an entirely different data shape, and lookup, which answers a related but distinct question.
Terraform contains vs. strcontains
contains and strcontains solve different problems, but the similar names can be a cause of confusion.
The strcontains function checks whether a substring exists inside a single string, working on plain strings rather than collections.
Put them side by side, and the difference is clear.
The above returns true because prod is an element in the first list.
This call also returns true, but for an entirely different reason. In this instance, prod is a substring inside one string, not a member of a list.
When you mix them up, it usually appears as an error about the wrong argument type, when people pass a string to contains expecting substring behavior, or pass a list to strcontains expecting membership behavior.
strcontains is newer to the language than contains; it shipped in Terraform 1.5.0, released in June 2023, so if you are on an older Terraform version (of the many versions in circulation), it may not be available.
Terraform contains vs. lookup
lookup retrieves a value from a map by key. It identifies what value sits behind a given key, with an optional default if that key is missing.
The rule of thumb is to use lookup when you already know the key and want the value stored under it in a map.
People sometimes mistakenly use lookup to test presence, checking whether the returned value equals a default, when a direct contains check against the map's keys would say the same thing more clearly.
Stategraph's perspective on Terraform contains
Stategraph does not change how contains, strcontains, or any other Terraform function behaves. Those are part of the Terraform language itself, and they work exactly the same whether or not Stategraph is involved.
Stategraph is useful in the layer above individual functions.
With a flat JSON state file, checking what actually exists in your infrastructure is a task that involves grepping or parsing text by hand. Stategraph stores states as structured data in a database, so instead of writing scripts to search a state file for a specific value, teams can query state directly with SQL and get an answer back immediately.
For a single contains check inside a variable validation block, you do not need any of that. For teams running more complex checks across state, working out which resources reference a given value, or confirming something is present across dozens of state files, structured querying is the natural next step past what a single Terraform function can do.
Read more about how Stategraph Inventory lets you query state directly with SQL, or try Stategraph free to see how it handles those checks at scale.
Related Terraform terms
- Terraform map variables: Wrapping a map in
values()beforecontainscan search it, covered above, is one pattern this guide goes into in depth. - Terraform CLI:
terraform consoleis the fastest way to test acontainsexpression before wiring it into validation or a resource conditional. - Terraform regex function: Reach for
regexorregexallwhen a plain membership or substring check isn't precise enough. - Terraform security: Validating a variable against an approved list with
containsis one of the concrete guardrails covered there.