Terraform vs CloudFormation on AWS — Which to Use
A practitioner's comparison of Terraform and CloudFormation on AWS covering state, drift, new-service lag, rollback, and where CDK fits.
Key takeaways
A practitioner's comparison of Terraform and CloudFormation on AWS covering state, drift, new-service lag, rollback, and where CDK fits.
On this page
Terraform vs CloudFormation on AWS — Which to Use#
Every AWS team eventually hits this fork. You need infrastructure as code, and the two obvious candidates are HashiCorp Terraform and AWS CloudFormation. Both provision real resources from declarative files. Both are mature. The wrong choice will not sink you, but it will shape how your team works for years, so it is worth getting right the first time.
Here is the short version before we dig in: if you are all-in on AWS and want zero extra tooling, CloudFormation is a defensible default. If you touch more than one cloud, or you want the module ecosystem and the ergonomics, Terraform usually wins. The details below are where the decision actually lives.
Multi-cloud vs AWS-only#
This is the cleanest dividing line. CloudFormation only provisions AWS resources. That is not a weakness so much as a scope decision. If your entire estate is AWS and you have no plans to change that, being AWS-only is fine, and it buys you first-party integration.
Terraform speaks to hundreds of providers through one workflow: AWS, Cloudflare, Datadog, GitHub, PagerDuty, Kubernetes, and so on. Most real teams provision more than just AWS resources. You configure a DNS record in Cloudflare, a monitor in Datadog, and a bucket in AWS in the same plan. CloudFormation cannot do that. Once you have any non-AWS resource under management, Terraform stops being optional.
State management: the biggest philosophical split#
CloudFormation manages state for you. AWS tracks what each stack owns on the service side. There is no state file to store, lock, or corrupt. That is genuinely less operational burden, and it is the feature people underrate most when they first compare the two.
Terraform keeps its own state file, and you are responsible for it. In practice that means a remote backend such as S3 with a DynamoDB lock table (or the newer S3-native locking), so concurrent runs do not stomp each other. State can drift from reality, get corrupted, or leak secrets if you are careless. The upside is that the state file is inspectable and manipulable. You can terraform state mv a resource, import existing infrastructure, or surgically remove something. That level of control has saved many migrations.
Drift detection: CloudFormation has native drift detection that reports when someone changed a resource in the console out from under the stack. Terraform surfaces drift every time you run terraform plan, which is arguably better because you see it on every apply rather than having to ask.
Speed of new-service support#
This one flips the usual narrative. CloudFormation frequently supports brand-new AWS services and properties on or near launch day, because it is built by the same company shipping the services. The Terraform AWS provider is maintained separately, so there is often a lag of days to weeks before a new resource or attribute lands in a released provider version.
If you live on the bleeding edge of AWS announcements, CloudFormation gets you there sooner. For most teams the lag rarely bites, because you are not adopting a service the week it ships. But when it does bite, it is annoying, and Terraform users end up reaching for the aws-cloudcontrol provider or raw API calls as a stopgap.
Rollback behavior#
CloudFormation rolls back automatically. If a stack update fails partway through, it reverts to the last known-good state by default. That is a real safety net and it is on by default with no extra work.
Terraform does not roll back. If an apply fails halfway, you are left in a partial state and you fix forward: read the error, adjust config, apply again. Some people love the automatic rollback, others find it maddening when a rollback itself gets stuck and leaves a stack in UPDATE_ROLLBACK_FAILED, which is a genuinely painful place to be. Neither model is strictly better. Terraform gives you control and expects competence; CloudFormation gives you guardrails and occasionally traps you inside them.
Ergonomics: HCL vs YAML/JSON#
Here is the same S3 bucket in both tools. First, Terraform HCL:
resource "aws_s3_bucket" "logs" {
bucket = "acme-app-logs-prod"
tags = {
Environment = "prod"
Team = "platform"
}
}
resource "aws_s3_bucket_versioning" "logs" {
bucket = aws_s3_bucket.logs.id
versioning_configuration {
status = "Enabled"
}
}
Now the CloudFormation equivalent in YAML:
Resources:
LogsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: acme-app-logs-prod
VersioningConfiguration:
Status: Enabled
Tags:
- Key: Environment
Value: prod
- Key: Team
Value: platform
HCL has real expressions, loops via for_each, conditionals, and interpolation that reads cleanly. CloudFormation YAML leans on intrinsic functions like !Ref, !Sub, and !GetAtt, which work but get verbose fast. For composition, CloudFormation offers nested stacks and StackSets. StackSets are legitimately strong for pushing the same stack across many accounts and regions in an AWS Organization, and Terraform has no exact one-to-one equivalent for that org-wide fan-out. Terraform counters with modules, which are more flexible for everyday reuse.
CDK as the escape hatch#
If you like CloudFormation's managed state and same-day service support but cannot stand YAML, the AWS CDK is the escape hatch. You write TypeScript, Python, or Go, and it synthesizes CloudFormation templates underneath. You get real programming constructs on top of the CloudFormation engine. It is a strong middle path for teams that want AWS-native deployment with actual code ergonomics. If you are weighing that route, our Pulumi vs AWS CDK piece goes deeper.
Module and registry ecosystem#
Terraform's Registry is a decisive advantage. There are well-maintained, community-vetted modules for VPCs, EKS clusters, RDS, and hundreds of other patterns. You pull in a battle-tested VPC module and skip a week of wiring subnets and route tables. CloudFormation has nothing equivalent at that scale. AWS Solutions and Quick Starts exist, but the breadth and momentum sit firmly with Terraform.
Making the call#
Reach for CloudFormation when your estate is entirely AWS, you value zero state management overhead, you deploy org-wide with StackSets, and you want new-service support on launch day. Reach for Terraform when you provision across multiple providers, you want the module ecosystem, you value HCL and inspectable state, or you want one workflow spanning your whole stack. Reach for CDK when you want CloudFormation's engine but real code.
The call we'd make#
For most teams shipping today, we reach for Terraform. The multi-provider reality of modern infrastructure, the Registry, and the ergonomics outweigh the state-management chore, which a proper S3 backend solves once and then fades into the background. We recommend CloudFormation, usually through CDK, when a team is strictly AWS-only, deploys across dozens of accounts with StackSets, and wants zero third-party tooling in the supply chain. Both are solid. The mistake is picking on vibes instead of matching the tool to how many clouds and accounts you actually run.
For the wider landscape beyond these two, see our guide to the best Infrastructure-as-Code tools.
Get the DevOps Troubleshooting Cheat Sheet
Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.
GitLab CI/CD Best Practices in 2026: Pipelines You Can Trust
A production-focused GitLab CI/CD guide: include/extends templates, rules and workflow, needs DAGs, cache vs artifacts, protected environments, masked/protected variables and Vault, built-in security scanning, and review apps — with copy-paste examples.
Ansible vs Terraform — Configuration vs Provisioning
Terraform provisions infrastructure and Ansible configures machines, so pitting them against each other is the wrong question to ask.
More from DevOps
Explore more articles in this category
Best Kubernetes IDE and GUI Tools in 2026
kubectl is fine until you're juggling five namespaces across three clusters. These are the tools that make that manageable, compared.
Chef vs Puppet vs Ansible: Configuration Management in 2026
One is agentless and Python-based, the other two run a persistent agent and a domain-specific language. The architecture difference matters more than the syntax.
PagerDuty vs Opsgenie: Choosing an Incident Alerting Tool
Both page the right person at 3am and both integrate with everything. The real differences show up in pricing structure, workflow depth, and who already owns the ecosystem around you.
You might have missed
Evergreen posts worth revisiting.