CloudFormation vs Terraform: Why AWS’ Native IaC Falls Behind
If you’ve ever had the misfortune of dealing with CloudFormation, you’ve probably encountered some version of rollback hell. You deploy a stack, something goes wrong, and now you’re stuck in an endless loop of failed updates. AWS’ solution? Delete the entire stack and start over—hope you enjoy losing everything you just spent hours debugging.
Meanwhile, Terraform offers a completely different experience. Instead of waiting for AWS to clean up after itself, Terraform manages state externally and allows for targeted updates. Need to modify a single resource? No problem. With CloudFormation, you might be forced to redeploy half your infrastructure just to make a simple change.
But rollback issues aren’t the only reason engineers hate working with CloudFormation. The slow update cycle is another major problem. AWS frequently launches new features, but CloudFormation often lags months (or even years) behind in supporting them. Need to deploy DynamoDB Global Tables or WAF GeoMatchSets? Sorry, CloudFormation still doesn’t support them. In contrast, Terraform updates its AWS provider much faster, sometimes within weeks of a new AWS feature release.
And let's not forget validation—or the lack thereof. CloudFormation doesn’t properly check for syntax errors before executing a deployment. That means you might wait 30 minutes for a stack to roll out, only for it to fail at the very last step due to a simple typo. Worse, rollback takes just as long, wasting an hour just to fix something as trivial as a misnamed parameter. With Terraform, syntax errors are caught upfront, and if something does fail, you can fix it without tearing everything down.
Another frustrating limitation of CloudFormation is its lack of support for referencing existing resources. Need to look up an existing VPC ID, IAM role, or S3 bucket? Too bad—you have to pass it in as a parameter. Terraform, on the other hand, provides data sources, allowing you to reference existing AWS resources dynamically. This makes it far easier to integrate with existing infrastructure rather than forcing everything into CloudFormation’s rigid stack model.
That said, Terraform isn’t perfect either. Managing a large state file in Terraform can be a nightmare, especially in environments with hundreds of resources. If the state file gets corrupted or lost, recovering from it can be a major pain. But tools like Terragrunt solve this problem by breaking infrastructure into smaller, independently managed modules, reducing the risk of state bloat.
Another common Terraform complaint is code duplication. Unlike CloudFormation, which supports nested stacks, Terraform lacks a built-in mechanism to reuse configurations across multiple environments easily. This leads to a lot of copy-pasting between dev, staging, and production. Again, Terragrunt steps in with its hierarchical configuration system, allowing you to define infrastructure once and reuse it across different environments without unnecessary duplication.
At the end of the day, if you’re deploying AWS-only infrastructure and don’t mind CloudFormation’s quirks, it might be tolerable. But for engineers who value speed, flexibility, and sanity, Terraform—especially with Terragrunt—is the clear winner.