CloudFormation vs. Terraform in 2024
An “Expert’s” Insight
Table of Contents
- Preface
- Ecosystem
- Compatibility/Support
- OpenSource vs. Licencing vs. Native
- Speed
- Associated Toolsets & Accessories
- Programming and Dev Experience
- Future of Both Tools
- Conclusion
Preface
My journey with IaC began in 2018, focusing exclusively on CloudFormation. Over the years, I honed my skills to become a Subject Matter Expert in CloudFormation while working at AWS. This involved a lot of things, mainly ,providing complex work evidence of solving CFN issues for customers and also passing a board with the CFN dev team in Seattle. However, since 2022, Terraform has beeen the go-to tool for all things IaC where I work.
This was quite a change, and while I still use CFN for a lot of my personal projects I’ve been using Terraform almost entirely in work apart from a few SAM stacks deployed via Terraform modules.
This transition offered me a unique perspective on both tools, and in this post, I’ll share my insights, comparing CloudFormation and Terraform across various dimensions when deploying infra to AWS. I’ll also show why I think CloudFormation is improving and closing the gap on Terraform and what I think is to come from both over the next few years.
Ecosystem
CloudFormation: As a native AWS service, CloudFormation is tightly integrated with AWS, providing out-of-the-box support for almost every AWS resource. Its ecosystem is robust, with a wealth of templates and a supportive community. However, it can be somewhat insular, primarily catering to AWS resources.
Terraform: Terraform’s ecosystem is expansive, supporting multiple providers beyond just AWS. Its modular approach, with the use of Terraform Registry, offers a vast collection of modules contributed by the community, enhancing its adaptability and extensibility across various cloud platforms and services.
Compatibility/Support
CloudFormation: CloudFormation launched back in 2011 and whether you view this as a pro or con any template written on Day 1 of CloudFormation can still be deployed today without issues or errors. For example, when working older, more mature code bases this can be a benefit during updates. AWS will always support that JSON or YAML template.
Whereas with Terraform, when you go to revisit your long running RDS DB that’s reaching EOL support, you’ll be faced with major upgrade changes for the terraform-provider-aws. Similarly, your template_files may no longer be supported and you need to spend time updating code to use the newer templatefile function. There’ll always be that management overhead when using Terraform.
Some other issues I’ve noticed creeping up recently are with resource AWS support and updates from Terraform.
At re:invent 2023 we got periodic recording for Config on November 26th, this was supposed to come with OOTB support from CloudFormation via the RecordingMode parameter, we didn’t get it that night but had to wait until December 11th via 1861 not too long considering it’s AWS’ busiest week of the year and a lot of staff are in Vegas:
Type: AWS::Config::ConfigurationRecorder
Properties:
[...]
RecordingGroup:
RecordingGroup
RecordingMode:
RecordingMode
[...]
But it took a whopping 3 months to reach Terraform support on February 23rd 2024 when it was delivered via 34577!
Similarly, with CodePipeline we got the V2 Pipeline Type for re:Invent week on November 22, 2023. This allows you to use a couple of new features but most importantly allowed you to avail of cheaper Pipeline costs via the new type. This came with same day support via CloudFormation PipelineType parameter.
This was brought to Terraform in January 2024 via 34122.
I’m not complaining about having to wait here and understand that the aws terraform provider is maintained by a small team, I just suspected these changes to be implemented at a quicker rate with the maturitity of the AWS provider. The speed of feature delivery is food for though when using these tools at scale.
Another example of gaps in support I was surprised to see were with data sources. To this day there’s no support for HTTP API Gateway custom domain name data blocks in Terraform, I suspect shortly after publishing this though it will be provided via 36027:
data "aws_apigatewayv2_domain_name" "example" {
domain_name = "api.example.com"
}
Some things Terraform should be commended on though, is its support for multiple providers and tooling. For example, if using CloudFormation and mTLS with API Gateway your only real native option is to use ACM Private CA to issue certificates with a checks AWS Bill cost of $400/month per certificate. If you’re using Terraform you can use the TLS Provider and self sign certs for your API gateways truststore:
###############################################
# S3 bucket and TLS certificate for truststore
###############################################
resource "aws_s3_bucket" "truststore" {
bucket = "${random_pet.this.id}-truststore"
# acl = "private"
}
resource "aws_s3_object" "truststore" {
bucket = aws_s3_bucket.truststore.bucket
key = "truststore.pem"
server_side_encryption = "AES256"
content = tls_self_signed_cert.example.cert_pem
}
resource "tls_private_key" "private_key" {
algorithm = "RSA"
}
resource "tls_self_signed_cert" "example" {
is_ca_certificate = true
private_key_pem = tls_private_key.private_key.private_key_pem
subject {
common_name = "example.com"
organization = "ACME Examples, Inc"
}
validity_period_hours = 12
allowed_uses = [
"cert_signing",
"server_auth",
]
}
The equivalent to the above is a lambda-backed custom resource in CFN, which would not be graceful at all. Using a mix of resource providers is where Terraform can outshine CloudFormation when deploying to AWS on occasions.
OpenSource vs. Licencing vs. Native
This is one the hottest topics recently in regards to CloudFormation vs. Terraform. In the past, a very strong argument to use Terraform was that it’s “open source”. However in 2023, HashiCorp threw a curve ball by adopting a Business Source Licence. I won’t go in to what’s involved in all of that in this post but you can think of services that used to be free and aren’t anymore.
Further, this sparked the creation of OpenTofu a truly open-source alternative. So with a lack of transparency from HashiCorp you’re faced with continuing to use Terraform and hope it remains free or seriously consider OpenTofu - not exactly a trivial task and something you want your dev team discussing. Anyone using CloudFormation won’t be having this conversation.
On the CloudFormation side, back in the day CloudFormation was a completely closed shop and owned by a dev team who were responsible for implementing all of the AWS’ resources in to CFN. As the number of services AWS created grew this became unsustainable, especially with 2 pizza teams - it was difficult to stay consistent.
Today, there’s still a CFN service team in AWS but they’ve built a platform where on launch other Service Teams in AWS must write their own provider code for CFN. This makes things consistent across all of the teams.
While I don’t see the CloudFormation engine ever becoming fully open-source a lot of the resource providers have been made available on GitHub here which is a welcome change to having to contact AWS Support directly for all resource issues and having no transparency in the past.
There’s also the cloudformation-coverage-roadmap which provides an amicable amount of transparency in to what is and isn’t coming to CloudFormation.
Speed
Speed of deployment has been talked about a lot in CFN vs. TF but I haven’t seen any legitimate benchmark data.
From personal use though, I do feel that Terraform is quicker to deploy. Especially for specific AWS resources such as CloudFront, R53 and IAM updates. However, some things do just take a while. For example, with ECS Services I know that CloudFormation won’t mark the resource as CREATE_COMPLETE until a task has reached the steady state it pings DescribeTask calls to achieve this which is known as Resource Stabilization.
Terraform feels quicker to re-deploy failed deployments too as it doesn’t rollback each resource similar to the way CloudFormation does. Also with Terraform you’d traditionally fail quicker if a resource type or variable did not match an expected value. With CloudFormation you would have only hit this at Stack Creation.
However, just this week CloudFormation announced the following - Experience up to 40% faster stack creation with AWS CloudFormation, I’m yet to experiment with this new CONFIGURATION_COMPLETE state but it looks like Stabilization is being performed in parallel now.
So while Terraform can be faster to deploy resources, you mightn’t get that baked in stabilisation that comes with CloudFormation. Terraform does have better parallelism capabilities though.
Associated Toolsets & Accessories
cdk migrate, tf lint, cfn lint, checkov, tfsec, aqua
Both tools here perform similarly in this regard with CloudFormation and Terraform both having tools to lint and enforce security best practice. cfn lint and tf lint both offer similar rule sets. cfn-guard also feels a lot like tfsec although the latter has faced a rename recently from tfsec to trivy - again something we don’t see with CloudFormation are renames.
When using Open Policy Agent CloudFormation allows you to use hooks which can be finicky with OPA as hooks only support Python or Java. Because of this, you need the OPA CFN Hook which does work. If you really want to use OPA with Terraform you’ll need to pay for Terraform Cloud:

checkov is also useful for both CFN and TF and is free for now. The CDK also supports features for validation during synthesis time via CfnGuardValidator and supports OPA and Chekov.
Programming and Dev Experience
The capabilities of HCL is where Terraform excels in comparison to CloudFormation. When using both these tools at scale you begin to face teething issues. While CloudFormation has a decent set of Pseudo parameters that can be used to enable multi-account, multi-region deploys such as AWS::AccountId & AWS::Region the Intrinsic Functions also work but aren’t a breeze to play with. They have expanded on these with recent additions via the AWS::LanguageExtensions transforms but again it’s a little convoluted.
When using CFN at scale with Nested Stacks you’ll also face issues with Imports/Exports and Cross-Stack references and dependencies. I’m sure anyone reading this will wince at the following error:
StackA Export StackA:ExportsOutputRefMyTableCD79AAA0A1504A18 cannot be deleted as it is in use by StackB
I would recommend avoiding these completely and using Parameter Store and dynamic references for non-sensitive values.
Terraforms development experience trumps CloudFormation here considerably. From my time working with tf there’s something useful there when you need to reference an existing resource or something else. For example, data sources for references, modules for re-usabilility, outputs for debugging and referencing values and the list goes on.
dynamic Blocks can also be extremely useful within modules when aiming to create slightly different variations of resources but re-use the same code. I haven’t even mentioned for_each or count. The list of built-in functions is endless too. You’ve also got the random provider to take care of dynamic placement of resources in subnets:
data "aws_availability_zones" "available" {
state = "available"
}
resource "random_shuffle" "az" {
input = data.aws_availability_zones.available.names
result_count = 3
}
CloudFormation definitely comes out second in this contest as the more primitive tool. For more “dev” DevOps Engineers and Software Engineers working at scale, Terraform will naturally be the preffered choice here.
Future of Both Tools
CloudFormation: As AWS continues to evolve, CloudFormation is expected to remain a key player, potentially expanding its capabilities and integration with other AWS services. Its future likely includes enhancements in usability and template management. With the additional abstraction of the CDK, I wonder will we ever see a rebuilt CFN engine that doesn’t translate go, typescript or python code back in to JSON or YAML templates like the CDK does - but today this is where we’re at.
Terraform: I’m not sure exactly where Terraform’s trajectory is going to go. With the introduction of Terraforms licencing, the recent creation of OpenTofu and the delays in introducing new resources I’m beginning to think that Terraform are going to push on Terraform Cloud and begin to cash in on what a great tool it has been over the years. I would not be surprised to see them enforce billing on Enterprise customers or be acquired this year. Having said that, I think they will look to develop towards broader ecosystem support and implement more providers.
Conclusion
Both CloudFormation and Terraform have their strengths and areas for improvement. My personal experience has shown me the nuances of each, and I believe the choice between them often depends mainly on the projects needs and organizational context. For example, anything multi-cloud you’re not choosing CloudFormation.
I like to think that within an enterprise you can use both. Either or. As long as there’s the correct tooling in place to use Terraform well and in a consistent manner. This is where the toolsets and accessories become more important.
I also wouldn’t turn anyone away from using the aws_cloudformation_stack terraform resource, while it may appear to be an antipattern it can combine the best of worlds at times.
Having said that, with the recent improvements CloudFormation has made and the changes in licencing and uncertainty from Terraform. I would have to crown the long term IaC winner in my opinion as … CloudFormation.