"The ops team here are debating whether they want to standardize upon CloudFormation or Terraform. The consensus seems to be veering towards Terraform."
"I can use CloudFormation, but I use Terraform when I can help it."
These are just some of the quotes I have heard about the two main competing infrastructure-as-code tools out there, CloudFormation and Terraform. Some might even say that Terraform is better, unless they are already familiar with CloudFormation and do not want to switch, or are AWS consultants and are just towing the company line. (Disclosure: I am an AWS consultant, but independent).
Thing is, I feel the critics of CloudFormation have really got the wrong end of the stick. (Where does that expression come from you ask? "The stick" was used in communal Roman latrines at a time when they did not have toilet paper. Yes - they shared a stick, and yes - they sometimes grabbed the wrong end. ANYWAY...)
CloudFormation is of AWS, by AWS, and for AWS. Terraform is by Hashicorp, and supports many cloud platforms out there.
CloudFormation wants you to write JSON or YAML files to describe your infrastructure, while Terraform is written in Hashicorp Configuration Language.
CloudFormation in its raw form is so bad that common best practices have emerged to work around its limitations and annoyances. Based on these, various tools have been created that generate the JSON/YAML CloudFormation templates, apply them in AWS, and manage dependencies between stacks, and are better at performing these actions than AWS's own tools.
These tools are much more powerful than Terraform, which has remained "just good enough" so there was no serious attempt to improve it apart from Hashicorp, who have released incremental changes. Everyone just uses it as-is. The pain factor has never got high enough to force anyone to develop their own tooling to seriously improve upon it.
Hashicorp recognises this: the next major Terraform release will have richer, language-like features. But it will still not have the power of a full, proper, extensible programming language behind it.
One of the major problems is that Terraform's only abstraction mechanism is modules, which are cumbersome, inflexible, and cannot read external settings without having to pass every variable along the complete chain of modules. Release 0.12 attempts to address this by allowing the passing of dicts or lists instead of just individual variables, however, so hopefully that will ease that pain somewhat.
CloudFormation tools, on the other hand, can let you pass complex data types, or even classes, around, or can just pull in shared values from some central store or the environment. They use regular, plain, simple code, and can hide as much complexity and abstraction as you want without having to fight a limiting configuration language.
It is no doubt that Terraform is miles ahead of CloudFormation in its raw JSON/YAML form, but then C is miles ahead of assembler code. We would still rather go up a few additional levels of abstraction to make our lives even easier - in both cases.
In reality, CloudFormation should not be treated as a competitor to Terraform (regardless of what AWS think). CloudFormation JSON/YAML templates are a compile time target, while Terraform is a configuration language not really designed to be outputted by anything else. Instead, StackMaster/Stacker/etc. should be compared to Terraform.
CloudFormation tools, due to their very nature of being of being based on a proper programming language, are much more powerful than any fancy configuration language. They can encapsulate more complexity behind simpler abstractions and can be extended much more easily. Furthermore, higher abstractions can more easily be built upon them and thus making new projects easier to start, and very large projects easier to manage.
CloudFormation tools can even interoperate, as they all compile down to the same basic primitives (CloudFormation stacks and exports) and run on the same platform (the CloudFormation service). For example, my favoured way of deploying serverless applications is to use Stacker or StackMaster for the infrastructure itself, while using AWS SAM to deploy the serverless functions themselves. The Serverless Framework can, for example, have arbitrary CloudFormation added to build resources that the framework does not natively support.
To be clear: Terraform is not a bad tool, and any project using it will be miles ahead of its competitors that are not using any infrastructure-as-code tool. It is really well designed and is easy to pick up and get started with. Also, both have different areas of specialization, e.g. custom resources in CloudFormation, or multi-cloud support (or non-AWS cloud support in general) in Terraform, so sometimes the choice is made for you.
But larger projects on AWS will derive greater benefits from the power of a proper programming language backing them up rather than a directory full of fancy configuration files.
Of course, it also gives you the power to shoot yourself in the foot (or a more sensitive area) but with great power, as they say...