Mastering Terraform Contains and Strcontains Functions
By Vladimir Mikhalev · Solutions Architect · Docker Captain · IBM Champion
Terraform is declarative. Which is a polite way of saying you don’t get if-statements like a normal programmer. You still need to validate inputs. You still need to gate deployments and steer behavior. So you reach for the logic tools the language actually hands you.
Two of them look trivial and turn out to be ridiculously useful: contains() and strcontains().
If a bad variable, a missing VM size, or a misnamed AZ has ever cost you a Saturday, read on.
Here’s how both work. No fluff.
contains(): is the value in there, or are you debugging all weekend
contains() checks whether a specific value sits inside a list or a set.
contains(list, value) => boolReturns true if the list has the value. false if it doesn’t. That’s the whole API.
Basic? Yes. But once your infra logic starts leaning on user input, region capabilities, or feature flags, this little function turns into the bouncer at the door of your Terraform nightclub.
Real example: Azure VM sizes
Picture someone on the team requesting a beefy VM in a tiny region that can’t host it. You want to catch that before the apply blows up.
variable "region" { default = "uksouth"}
variable "vm_size" { default = "Standard_DS2_v2"}
data "azurerm_virtual_machine_sizes" "example" { location = var.region}
output "is_supported" { value = contains(data.azurerm_virtual_machine_sizes.example.sizes, var.vm_size)}If vm_size isn’t offered in that region, you get false. Feed that into a count, a for_each, or a validation block. Whatever you pick, it beats watching Terraform barf mid-deploy.
strcontains(): when you’re parsing strings like it’s bash again
Now strcontains(). This is Terraform answering one question: does this string have that other string inside it?
strcontains(string, substr) => boolReach for it when there’s no list, just a single string. An AZ name, a tag, a label. You want to match a pattern in it.
Example: is this AZ optimized
strcontains("us-east-1b-optimal", "optimal") // returns trueIt earns its keep when providers or modules hand back strings with metadata baked in and you need to route logic off that.
Say you only want to deploy when the target zone is labeled “optimal”:
locals { is_optimal_zone = strcontains(var.availability_zone, "optimal")}Now local.is_optimal_zone is your switch. Use it to create resources, set tags, add taints, whatever the condition gates.
Gotchas that bit me, so they don’t bite you
contains()wants the exact value. Case-sensitive. No fuzzy matching.strcontains()doesn’t do regex or wildcards. Pure substring, nothing more.- Maps don’t behave with
contains()the way you’d hope. Lists and sets only. Trycontains({ key = "val" }, "key")and you’ll be disappointed. - Nulls can wreck your results. Validate your variables, or wrap them in
coalesce()when it matters.
Bonus: validate with style
Want to enforce rules on inputs? Drop these functions into validation blocks.
variable "az" { type = string default = "us-east-1b-optimal"
validation { condition = strcontains(var.az, "optimal") error_message = "Only 'optimal' AZs are allowed for this deployment." }}Now Terraform fails early, with a message a human can read, instead of crashing halfway through the plan.
TL;DR
- Reach for
contains()with lists or sets. - Reach for
strcontains()for substring checks on a single string. - Pair them with
validation,count, orfor_eachfor logic that stays clean and safe inside your modules. - Don’t guess. Test.
The Verdict
Inconvenient truths about shipping in the AI era
Container security, platform engineering, and the agentic shift — tested in production, argued without the hype. The verdict reaches your inbox the moment there's one worth sending.
Related Posts
- 1Terraform MCP server GA: the Apply Gate your auditor will ask aboutDevOps & Cloud · HashiCorp's Terraform MCP server is GA and IBM Bob can write production IaC. ENABLE_TF_OPERATIONS separates a safe assistant from autonomous apply.
- 2Docker supply chain hardening — from Scout D to OpenSSF 7.8 on a 730K-pull imageDevOps & Cloud · How I hardened a 730K-pull public Docker image from Scout grade D to OpenSSF Scorecard 7.8. Multi-stage build, cosign signing, SLSA provenance, non-root default, and the incident that changed how I ship attestations.
- 3Cloudflare Web Analytics on Astro — Why Removing GA4 Unlocked Lighthouse 100DevOps & Cloud · How removing Google Analytics 4 from an Astro site unlocked Lighthouse 100, why Cloudflare Web Analytics replaced it, and what the tradeoffs actually cost.
- 4Platform Engineering — The Complete, Practical Guide to Building Internal Developer Platforms That ScaleDevOps & Cloud · A deep, practical guide to Platform Engineering. Learn how to build internal developer platforms, golden paths, GitOps workflows, and scalable cloud foundations.
Random Posts
- 1Export Drivers Using Windows PowerShellSysAdmin & IT Pro · Learn how to export Windows drivers using PowerShell with the Export-WindowsDriver cmdlet. Step-by-step guide for automation and IT pros.
- 2Install OpenJDK on Ubuntu ServerSysAdmin & IT Pro · Step-by-step guide to installing OpenJDK on Ubuntu Server. Learn how to configure Java, set JAVA_HOME, and verify your environment for Java development.
- 3Install Rocket.Chat Using Docker ComposeSelf-Hosting · Step-by-step guide to install Rocket.Chat on Ubuntu Server using Docker Compose and Traefik with Let's Encrypt SSL. Ideal for secure team communication..
- 4Configure Amazon S3 for Rocket.Chat File SharingDevOps & Cloud · Step-by-step guide to integrate Amazon S3 with Rocket.Chat for secure file sharing. Learn bucket setup, IAM policies, and S3 configuration best practices.