Back to Terraform & IaC
Q2Question 2 of 13

Terraform vs CloudFormation: differences and how to choose for all-AWS

Key Concepts
  • CloudFormation only manages AWS resources; Terraform manages hundreds of providers including AWS, GCP, Azure, Kubernetes, PagerDuty, and GitHub.
  • CloudFormation manages state invisibly on the AWS side; Terraform requires you to store, encrypt, version, and lock state yourself.
  • CloudFormation automatically rolls back a failed Stack update; Terraform does not auto-rollback and you fix forward.
  • CloudFormation previews changes with Change Sets; Terraform previews with terraform plan.
  • Terraform's HCL is generally more readable with first-class loops and conditionals; CloudFormation YAML can be verbose.
  • For all-AWS with minimal overhead, CloudFormation is a strong choice; for multi-cloud or existing HCL teams, Terraform wins.
  • The decision is often about team skills and existing investment rather than technical features.

Definition

CloudFormation is AWS-native with managed state and automatic rollback; Terraform is multi-cloud with a plugin ecosystem and self-managed state.
  • CloudFormation -- AWS's native IaC service that uses YAML or JSON templates, works only within AWS, and manages state automatically as part of a Stack.
  • Terraform -- HashiCorp's cloud-agnostic IaC tool that uses HCL, supports hundreds of providers through plugins, and requires you to manage state yourself.
  • Change Set -- CloudFormation's preview mechanism that shows what a Stack update will do before you execute it.
  • terraform plan -- Terraform's equivalent preview that shows the diff without changing anything.
  • Automatic rollback -- CloudFormation's safety feature that reverts a failed Stack update to the last good state.
  • Fix-forward -- Terraform's approach where a failed apply leaves you partway and you edit and re-apply to resolve.

Think of two ways National Bank of India can furnish its branches. CloudFormation is like the approved in-house interior company that works only for this bank -- it knows every bank-specific rule, keeps the paperwork in its own cabinet, and is perfectly tuned to this bank, but you can never use it for another building. Terraform is like an independent contractor who can furnish a bank, a shop, or a hospital anywhere -- more flexible, works across many types, but you keep your own records and lock the site so two crews do not clash.

Understanding the Concepts

What is the scope difference?

CloudFormation only manages AWS resources. Terraform is provider-agnostic and manages AWS, Google Cloud, Azure, Kubernetes, GitHub, Datadog, PagerDuty, and hundreds more through its plugin ecosystem. For a bank that uses AWS for compute but also manages PagerDuty, GitHub, and Cloudflare as code, Terraform can do all of that from one place.

HCL
# Terraform: manage AWS and PagerDuty in one place
provider "aws" {
  region = "ap-south-1"
}

provider "pagerduty" {
  token = var.pagerduty_token
}

resource "aws_sqs_queue" "alerts" {
  name = "nbi-fraud-alerts"
}

resource "pagerduty_service" "fraud" {
  name        = "NBI Fraud Service"
  escalation_policy = pagerduty_escalation_policy.banking.id
}
YAML
# CloudFormation: AWS only
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  AlertsQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: nbi-fraud-alerts
# Cannot manage PagerDuty from here

How does the language differ?

CloudFormation uses YAML or JSON with named sections -- Resources, Parameters, Mappings, Outputs, Conditions. Terraform uses HCL with first-class loops, conditionals, and expressions. HCL is generally more concise and readable.

HCL
# Terraform: create 3 SQS queues with for_each
resource "aws_sqs_queue" "service_queues" {
  for_each = toset(["ledger", "payments", "fraud"])
  name     = "nbi-${each.key}-queue"
}
YAML
# CloudFormation: more verbose, no native for_each
Resources:
  LedgerQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: nbi-ledger-queue
  PaymentsQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: nbi-payments-queue
  FraudQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: nbi-fraud-queue

How does state management differ?

Terraform keeps an explicit state file that you own. You must store it remotely, encrypt it, version it, and lock it. CloudFormation manages state invisibly on the AWS side as part of the Stack. You never see or store a state file.

HCL
# Terraform: you configure and manage state
terraform {
  backend "s3" {
    bucket         = "nbi-tf-state"
    key            = "fraud/production/terraform.tfstate"
    region         = "ap-south-1"
    dynamodb_table = "nbi-tf-locks"
    encrypt        = true
  }
}
YAML
# CloudFormation: state is invisible, managed by AWS
# You just create or update the Stack
# aws cloudformation create-stack --stack-name nbi-fraud --template-body file://template.yaml

How do change preview and failure handling differ?

Terraform previews with terraform plan. CloudFormation previews with Change Sets. On failure, CloudFormation automatically rolls the entire Stack back to the last good state. Terraform does not auto-rollback -- a failed apply leaves you partway, and you fix forward by editing and re-applying.

BASH
# Terraform: preview with plan
terraform plan

# CloudFormation: preview with Change Set
aws cloudformation create-change-set \
  --stack-name nbi-fraud \
  --template-body file://template.yaml \
  --change-set-name fraud-update-001

aws cloudformation describe-change-set \
  --stack-name nbi-fraud \
  --change-set-name fraud-update-001
TEXT
# CloudFormation Change Set output
Changes:
  - Action: Modify
    ResourceType: AWS::SQS::Queue
    LogicalResourceId: AlertsQueue
    Replacement: False

How does drift detection work in each?

CloudFormation has built-in drift detection -- you ask a Stack whether anyone changed it by hand. Terraform detects drift as a side effect of the next plan.

BASH
# CloudFormation: explicit drift detection
aws cloudformation detect-stack-drift --stack-name nbi-fraud
aws cloudformation describe-stack-drift-detection-status \
  --stack-drift-detection-id abc-123
BASH
# Terraform: drift shows up automatically in the next plan
terraform plan
TEXT
  # aws_sqs_queue.alerts has been changed outside Terraform
  ~ resource "aws_sqs_queue" "alerts" {
      ~ visibility_timeout_seconds = 60 -> 30
    }

How do you choose for an all-AWS environment?

If you are genuinely only on AWS and want the least operational overhead, CloudFormation is a strong choice -- AWS manages state, rollback is automatic, and integration with Service Catalog and drift detection is seamless. You choose Terraform when you have multiple clouds, many non-AWS SaaS tools to manage, or your team already knows HCL.

| Criterion | Choose CloudFormation | Choose Terraform |
|---|---|---|
| Cloud scope | AWS only, forever | Multi-cloud or SaaS tools |
| State management | Want zero state chores | Want direct state control |
| Failure handling | Prefer automatic rollback | Comfortable with fix-forward |
| Team skills | Team knows YAML/CFN | Team knows HCL |
| Ecosystem | AWS-native integrations | Huge module registry |

What about AWS CDK?

AWS CDK lets you generate CloudFormation templates from real programming languages like TypeScript, Python, or Java. It is a higher-level abstraction that synthesizes down to CloudFormation YAML. CDK gives you the programming power of a real language with CloudFormation's managed state and rollback.

JAVA
package com.bank.cdk;

import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.services.sqs.Queue;
import software.constructs.Construct;

public class FraudStack extends Stack {

    public FraudStack(final Construct scope, final String id) {
        super(scope, id);

        Queue.Builder.create(this, "FraudAlerts")
            .queueName("nbi-fraud-alerts")
            .retentionPeriod(software.amazon.awscdk.Duration.days(14))
            .build();
    }

    public static void main(String[] args) {
        App app = new App();
        new FraudStack(app, "NbiFraudStack");
        app.synth();
    }
}
BASH
cdk synth   # generates CloudFormation YAML
cdk diff    # equivalent to terraform plan
cdk deploy  # equivalent to terraform apply

What should a senior engineer know?

The decision is often less about features and more about team skills and existing investment. If the whole platform org already runs Terraform with remote state and locking, adding CloudFormation just for AWS fragments the toolchain, and consistency usually wins. Both tools are mature and production-proven at banks. The application code never cares which tool built the infrastructure -- it just reads a queue URL from an environment variable.

JAVA
package com.bank.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class FraudAlertService {

    // Same code regardless of whether Terraform or CFN built the queue
    @Value("${aws.sqs.fraud-alerts-url}")
    private String queueUrl;

    public void publishAlert(String accountId, String reason) {
        // Application does not know or care which IaC tool created the queue
        System.out.println("Publishing fraud alert for " + accountId
            + " to " + queueUrl);
    }
}
TEXT
Publishing fraud alert for SAV2001 to https://sqs.ap-south-1.amazonaws.com/123456789/nbi-fraud-alerts

Visual Overview

DIAGRAM
  Terraform vs CloudFormation
  ───────────────────────────

  Terraform                          CloudFormation
  ─────────                          ──────────────
  ┌──────────────┐                   ┌──────────────┐
  │  .tf files    │                   │  YAML/JSON    │
  │  (HCL)        │                   │  template     │
  └──────┬───────┘                   └──────┬───────┘
         │                                  │
         ▼                                  ▼
  ┌──────────────┐                   ┌──────────────┐
  │ terraform     │                   │ Change Set    │
  │ plan          │                   │ (preview)     │
  └──────┬───────┘                   └──────┬───────┘
         │                                  │
         ▼                                  ▼
  ┌──────────────┐                   ┌──────────────┐
  │ terraform     │                   │ Execute       │
  │ apply         │                   │ Change Set    │
  └──────┬───────┘                   └──────┬───────┘
         │                                  │
         ▼                                  ▼
  ┌──────────────┐                   ┌──────────────┐
  │ State in S3   │                   │ State managed │
  │ (you manage)  │                   │ by AWS (auto) │
  └──────────────┘                   └──────────────┘

  On Failure:
  Terraform: partial apply, fix forward
  CloudFormation: automatic rollback to last good state

  Scope:
  Terraform: AWS + GCP + Azure + K8s + PagerDuty + GitHub + ...
  CloudFormation: AWS only

Key Takeaway

Terraform and CloudFormation are both Infrastructure as Code tools, but they differ in three fundamental ways. Scope: CloudFormation only manages AWS resources, while Terraform manages hundreds of providers through its plugin ecosystem. State: Terraform keeps an explicit state file you must store, encrypt, and lock yourself, while CloudFormation manages state invisibly on the AWS side. Failure handling: CloudFormation automatically rolls back a failed update, while Terraform does not auto-rollback and you fix forward.

For an all-AWS environment, CloudFormation is a legitimate choice if you want the least operational overhead -- AWS manages state, rollback is automatic, and drift detection is built in. Terraform wins when there are multiple clouds, many non-AWS tools to manage, or the team already knows HCL and values the module ecosystem. AWS CDK bridges the gap by letting you write real programming languages that synthesize to CloudFormation.

In practice, the decision is less about features and more about team skills and existing investment. If the platform org already runs Terraform with remote state and locking, adding CloudFormation fragments the toolchain and consistency wins. The application code never cares which tool built the infrastructure.

Remember one sentence: CloudFormation is AWS-native with managed state and automatic rollback, Terraform is multi-cloud with a plugin ecosystem and self-managed state, and the choice depends on team skills and multi-cloud needs.

---

Share
Use ← → arrow keys to navigate