Infrastructure as Code on AWS: Terraform vs CloudFormation vs CDK

Infrastructure as Code on AWS: Terraform vs CloudFormation vs CDK


Introduction: Why Infrastructure as Code Matters


Meet Nebula, a fast-growing startup. At first, they built everything by hand in the AWS console: a VPC here, a couple of subnets there, an EC2 instance for their app, and an S3 bucket for storage. It worked fine — until they needed to replicate the setup for staging, testing, and production.

Suddenly, chaos.

One engineer forgot a security group rule, another set up IAM roles differently, and no one could guarantee that environments were identical. Moving to another AWS region? Even harder.

This is the moment Nebula realized: they needed Infrastructure as Code (IaC).

By describing infrastructure as text, you get:

  • Consistency: every environment (dev, staging, prod) looks the same.
  • Version control: track changes just like application code.
  • Automation: no more endless clicking in the console.
  • Speed: spin up or tear down environments in minutes.

On AWS, three tools dominate the IaC landscape: Terraform, CloudFormation, and the AWS Cloud Development Kit (CDK). Each has strengths and trade-offs. Let’s see how Nebula’s team explored them.

What is Infrastructure as Code?


IaC allows you to describe complex infrastructure with text files (declarative or imperative), which can be version-controlled and automated. This eliminates manual configuration through the console, reduces human error, and improves collaboration across teams.

Terraform


Nebula’s engineers first tried Terraform, built by HashiCorp. They liked that it wasn’t tied to AWS — it supports Azure, GCP, Kubernetes, and dozens of other providers.

Pros:

  • Multi-cloud and provider-agnostic
  • Large community and plenty of reusable modules (Terraform Registry)
  • Simple, readable HCL syntax
  • Mature workflow (plan → apply → destroy)

Cons:

  • External tool, not AWS-native
  • State file (.tfstate) management can be tricky without a remote backend (S3 + DynamoDB)
  • Debugging errors isn’t always straightforward

Example: Create an S3 bucket with Terraform


resource "aws_s3_bucket" "example" {
  bucket = "my-terraform-bucket"
  acl    = "private"
}

A few lines of code and your bucket is ready. Run terraform plan to see what will change, then terraform apply to deploy.

Best for: teams working in multi-cloud setups or those who want maximum flexibility beyond AWS-native solutions.

CloudFormation

Next, Nebula explored AWS CloudFormation, the native choice. The team loved how tightly it integrates with IAM, CloudWatch, and CodePipeline. And AWS handles state behind the scenes.

Pros:

  • Native and always up-to-date with new AWS services
  • No state file management (handled by AWS)
  • Tight integration with AWS services (IAM, CloudWatch, CodePipeline)
  • StackSets for managing resources across multiple accounts/regions

Cons:

  • Verbose: YAML/JSON templates get long and hard to maintain
  • AWS-only (no multi-cloud support)
  • Deployment error messages can be difficult to interpret

Example: Create an S3 bucket with CloudFormation

Resources:
  MyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-cfn-bucket

Compared to Terraform, it’s more verbose, but it’s deeply integrated into AWS (e.g., with StackSets you can deploy across accounts and regions easily).

Best for: teams working exclusively on AWS with a need for tight integration and compliance.

AWS CDK

Finally, Nebula’s developers tried the AWS Cloud Development Kit (CDK). They loved writing infrastructure with real programming languages (TypeScript, Python, Java, C#). It felt like “real code,” with loops, conditions, and abstractions.

Pros:

  • True “infrastructure as code” with loops, conditions, and functions
  • Ability to reuse constructs and libraries (define patterns and replicate them)
  • Ideal for developers already comfortable with programming languages
  • Maintains compatibility with CloudFormation

Cons:

  • Steeper learning curve for DevOps engineers less comfortable with coding
  • Relatively new; smaller community compared to Terraform
  • Debugging can be challenging if you’re not familiar with CloudFormation

Example: Create an S3 bucket with CDK (TypeScript)


import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';

export class MyStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    new s3.Bucket(this, 'MyCdkBucket', {
      bucketName: 'my-cdk-bucket',
      versioned: true
    });
  }
}

Instead of static templates, you can use loops, conditions, and reusable constructs. Under the hood, CDK compiles this into CloudFormation.

Best for: developer-heavy teams who want a modular and programmable approach to AWS infrastructure.

Quick Comparison

Feature Terraform CloudFormation AWS CDK
Multi-cloud Yes No No
Syntax HCL
(declarative)
YAML / JSON
(declarative)
TypeScript
Python
Java
(imperative)
State management Manual
(S3, DynamoDB)
Managed
by AWS
Managed
by AWS
Community Large AWS-focused Growing
Readability Good Poor
(verbose)
Depends
on language
Best fit Multi-cloud
& DevOps
AWS-only
enterprises
Developer-heavy
AWS teams

Real-World Scenarios

  • Startup going multi-cloud: Terraform is ideal — one tool across providers.
  • Enterprise with strict compliance: CloudFormation wins — AWS-native, tightly controlled.
  • Developer-heavy product team: CDK fits best — infrastructure and app code in the same repo.

At Nebula, the team even experimented with a hybrid approach: Terraform for cross-cloud resources, CDK for developer-focused services.

Practical Tips Before You Choose

  • Start small: try an S3 bucket with all three tools.
  • Use version control: Git + PRs = safer infrastructure.
  • Plan for state: Terraform needs remote state, CloudFormation/CDK don’t.
  • Mix carefully: hybrid approaches can work, but avoid overlapping chaos.

Conclusion: Which One Should You Choose?

It depends on your context:

  • Terraform → multi-cloud flexibility.
  • CloudFormation → AWS-only compliance and enterprise scale.
  • CDK → developer-centric, modular AWS teams.

Nebula’s story teaches us there’s no single winner. Many organizations use more than one tool side by side. What matters most is:

  • Stay consistent
  • Version your infrastructure
  • Follow DevOps best practices

That’s how IaC scales with your business.