When you want to implement infrastructure as code, you always come to the question if you should use CloudFormation or HashiCorp's open-source tool Terraform. Both have their advantages and disadvantages. I compared both in the following table to help you decide which tool is best suited for your needs.
Since there was a lot of feedback that you would like to have a comparison including the AWS CDK, I expanded the table by one column for the AWS CDK. I hope the table will help you to make the decision for the right tool for you.
⁉️ Some people asked me to add Pulumi as well to the table - here is your update 🚀.
|Supported AWS Resources||500+||500+||400+||400+|
|Third Party||➖ Open-source with support from AWS.||➖ Free with support from AWS and large community.||➖ Open-source with support from Hashicorp and large community.||➖ Open-source with support from Pulimi and large community.|
|CLI||✅ CDK CLI enables you to list the stacks defined in your CDK app, synthesize the stacks into CloudFormation templates, determine the differences between running stack instances and the stacks defined in your CDK code and deploy stacks to any public AWS Region.||✅ CloudFormation has a CLI that enables you to develop and test AWS and third-party resources and register them for use in AWS CloudFormation.||✅ Terraform has a single command-line application.||✅ Pulumi has a single command-line application.|
|Modularization||✅ CDK supports modules to create a reproducible infrastructure.||➖ Nested stacks and cross-stack references can be used to achieve modularization.||✅ Terraform modules help to create a reproducible infrastructure.||✅ Pulumi modules help to create a reproducible infrastructure.|
|State Management||✅ Deploys CloudFormation Stacks to manage its state.||✅ Uses Stacks to manage its state.||✅ By default saves the state locally but it is possible to save the state in Terraform Cloud, S3 or DynamoDB with the remote state feature.||✅ Pulumi saves the state (called checkpoint) locally but it is possible to save the state in Pulumi service backend or S3.|
|Configuration||✅ Supports Environment Variables, CloudFormation Parameters or you can get values from SSM.||✅ Supports up to 60 Parameters. Import values from output of another stack or import from SSM.||✅ Data sources allow data to be fetched or computed for use elsewhere in Terraform configuration.||✅ Pulumi offers a Config object with various getters and setters for retrieving values, in addition they have Data sources that allow to grep, for example an AMI or an AZ from AWS.|
|Change management||✅ cdk diff compares the desired state against the stack but it doesn't look at the deployed resources until you deploy. You only find out about discrepancies between the stack and deployed resources at deployment time.||✅ Change Sets help you to verify changes before you apply them on your stack.||✅ terraform plan creates a detailed execution plan before applying your changes.||✅ pulumi preview previews your changes explicitly before deploying.|
|Error handling and rollback||✅ AutoRollbackConfig helps you to configure the behavior of automatically rolling back for a given Deployment Group.||✅ CloudFormation automatically rolls back to the last working state.||❌||❌ Currently there is no rollback functionality in Pulumi but there is an open RFC to implement this functionality.|
|Import Existing Resources||❌ Currently its not possible to import resources into CDK, but there is an open RFC to implement this functionality. Additional information - there are workarounds how to use existing resources in CDK.||➖ It is possible to import resources into CloudFormation but only for a few resources.||➖ It is possible to import resources into terraform but it does not generate configuration.||✅ Pulumi offers an import resource option to request that a resource defined in your Pulumi program adopts an existing resource in the cloud provider instead of creating a new one.|
|Rolling updates for Auto-Scaling Groups||✅||✅||✅ You can implement rolling updates for Auto-Scaling Groups using the create before destroy lifecycle policy.||✅ You can implement rolling updates for Auto-Scaling Groups using the createBeforeDestroy lifecycle policy.|
|External waiting conditions||✅ You can use CfnWaitCondition to coordinate resource creation with configuration actions that are external to the stack creation.||✅ You can use WaitCondition to coordinate resource creation with configuration actions that are external to the stack creation.||✅ You can use null_resource to coordinate resource creation with configuration actions that are external to native Terraform resources.||✅ You pass a customTimeouts object as part of resource options to coordinate resource creation with configuration actions that are external to the resource.|
|Visualization of dependencies||✅ CDK has a plugin for Visual Studio Code which visualizes dependencies or you can use the cli.||✅ You can use the AWS CloudFormation Designer to view CloudFormation templates.||✅ You can use the terraform graph command to generate a visual representation of either a configuration or execution plan.||✅ You can use pulumi stack graph to export a stack’s dependency graph to a file.|
|Integration of new features after announcement||➖ After announcement of a new feature there is always a delay until it is integrated into CDK, but you can use Escape Hatches to workaround these missing features.||➖ After announcement of a new feature there is always a delay until it is integrated into CloudFormation, but as a workaround you can develop custom resources to cover new features.||➖ After announcement of a new feature there is always a delay until it is integrated into Terraform, but as a workaround you can use terraform-aws-anything to cover new features.||➖ After announcement of a new feature there is always a delay until it is integrated into Pulumi.|