I am sure you all find tons of information by googling around on this topic and you would definitely hit many flavors of creating stack on AWS Cloud. There are quite a few good better ways of creating AWS resources in a declarative way especially with CLI. I am sharing my experience with Cloudformation and Terraform in nutshell for those want to get a first hand information.
|Declarative templates||Yes. JOSN/YML formats||Yes. JSON/HCL which is based on libucl. HCL is recommended.|
|Trigger Bash commands and post processing steps||Yes||Yes|
|License and Support||Its part of AWS account||Open Source and option to go for enterprise support|
|CLI||yes, downloadable||yes, downloadable|
|Target users / provider support||only AWS Cloud||Yes greatly with AWS but supports other cloud providers such as OpenStack, Azure, Google etc.,|
|Generic resource syntax / Generic model mapper for to use across providers?||— Not applicable —||NO. Though they support many providers but your declarative templates needs to be specific to the target providers.|
|Stack – State Management||Its part of Cloudformation offerings and it manages thru change sets.||Stored in local disk but option to use remote state like in S3 or S3+DynamoDb for lock sync.note: if you accidently delete the state file either in remote or local then you won’t be able to destroy or apply updates to a stack|
|Reusable templates||Available and it can be maintained modular. Support for nested stacks.Reusable templates by passing values from external files/JSON.||Modules are kind of reusable packages where in you can import them via source attribute of a module definition.Nesting can be done but it should be kept in a folder called module like a parent and child modules but reusability of parent module across stack is in question.
Reusable templates by passing values from external files/JSON.
|verify stack updates before apply changes||Yes but if you updating Stacks Using Change Sets||It provides you an execution plan before apply changes.|
|Rolling back changes / or in the event of failures during update stack||Yes possible if you use Change Sets||Not possible.|
|Wait Handling||Yes possible to implement a wait condition for a AWS resource to be ready until to apply another changes||Not possible and often plan breaks because of this. There are situations your update will go thru if you rerun again because of this wait issue. Google for work arounds.|
|Use of existing resource references in templates||Either input manually or parameterize inputs but no way to query AWS to find existing a resource dynamically and reference them in your template.||It allows you to reference existing resource via data source mechanism which is a great plus.|
|Visualization||AWS offers a designer, export/import templates into it and its pretty cool||CLI tool creates a DOT format for a given plan and you would need to use a graphviz tool to render as an image. However the image is very large depends on how big your plan so you would need a plotter to print to go over.|
In my personal opinion, I would side with CloudFormation for now as it gives what one need for AWS standpoint. Also considering huge community behind AWS, AWS support, up-to-date SDK/CLI/APIs etc., putting me easy to maintain than Terraform. However I like Terraform declarative module approach and HCL simplicity over JSON but still it lacks maturity over generic models to many providers. I see majority of the Terraform community using towards AWS and if you look at Terraform registry, it is evident that number of modules available for AWS is greater than other providers. Terraform users would have to maintain Cloudformation scripts as well in quite a good of areas where it lacks support from Terraform. However its your call!