A while back I kept running into the same blog post, recycled under different titles: “you don’t need Terragrunt anymore, Terraform modules do everything it did.” Different authors, same argument. Terraform grew for_each on modules, got import blocks, got better state management. So the story goes: Terragrunt was a workaround for a young Terraform, and now that Terraform grew up, you can drop the wrapper and go back to plain HCL.
I’ve watched a handful of companies read that post and act on it. Rip Terragrunt out, migrate everything to “clean” Terraform modules, write a triumphant internal Slack message about it. A year later, some of those same teams are quietly rebuilding pieces of what they threw away, just with worse names and no docs.
Here’s my problem with the argument: it compares the wrong things. Terraform is a provisioning language. It’s very good at describing a pile of resources and reconciling reality against that description. Terragrunt was never trying to be a better version of that. It’s a composition tool: it decides what gets run, in what order, with what config, against which state. Modules answer, “How do I build a VPC?” Terragrunt answers, “How many VPCs do I have, where do they live, and how do I see all of them at once?” Those are different questions. Reading module for_each support as a replacement for Terragrunt is like reading “we added folders to our filesystem” as a replacement for Git.
I want to walk through why, using a real migration I just did. Not a toy example. An actual repo, actual GCP project, actual GitHub org, actual scars.
Read more: Terraform gives you modules. Terragrunt gives you a map.




