AWS Builder Center
Infrastructure as Code on AWS: CloudFormation, CDK and Terraform Explained

Infrastructure as Code on AWS: CloudFormation, CDK and Terraform Explained

Stop clicking through the console. Learn what Infrastructure as Code is, how AWS CloudFormation and CDK approach it, and how Terraform works, with a hands-on S3 example and tips for choosing the right tool.

The problem with "click-ops"

Most of us start on AWS by clicking through the console: create a VPC, launch an EC2 instance, attach a security group. It works, until you need to rebuild the same setup for a test environment, or someone asks "who changed that security group?" and nobody knows.
Infrastructure as Code (IaC) solves this by describing your infrastructure in files instead of clicks.

What is Infrastructure as Code?

Infrastructure as Code is the practice of defining and managing cloud resources (networks, servers, databases, permissions) through code that can be versioned, reviewed, tested and reused.
šŸ“· Insert image: iac-workflow.png
Why teams adopt it:
  • Repeatable: the same code builds identical dev, test and prod environments.
  • Version controlled: every change lives in Git, with history, pull requests and easy rollback.
  • Faster: a full environment comes up in minutes, not an afternoon of clicking.
  • Less human error: no forgotten settings or "it worked on my account" surprises.
  • Documented by default: the code is the documentation of what you run.

Declarative vs imperative

  • Declarative: you describe the end state ("I want one S3 bucket with versioning on") and the tool works out the steps. CloudFormation and Terraform work this way.
  • Imperative: you write the steps yourself, such as a shell script calling the AWS CLI.
Declarative tools are also idempotent: running them twice doesn't create duplicates, it only fixes differences.

IaC on AWS: native options

AWS CloudFormation

CloudFormation is AWS's built-in IaC service. You write a template in YAML or JSON, and CloudFormation creates the resources as a stack.
  • Change sets preview what will change before you apply it.
  • Drift detection shows resources changed outside the template.
  • Automatic rollback if a deployment fails.
  • AWS manages the state for you, so there is no state file to store.
1
2
3
4
5
6
Resources:
DemoBucket:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Enabled

AWS CDK (Cloud Development Kit)

The CDK lets you define infrastructure in languages like TypeScript, Python, Java, C# and Go. Your code is synthesized into a CloudFormation template and deployed through CloudFormation. It's a good fit if your team prefers real programming languages, with loops, functions and classes.

What is Terraform?

Terraform is an open-source IaC tool from HashiCorp. You write configuration in HCL (HashiCorp Configuration Language), and Terraform talks to cloud APIs through plugins called providers. Because providers exist for AWS, Azure, Google Cloud, Kubernetes, GitHub and many more, one tool and one workflow can manage all of them.

Core concepts

ConceptWhat it means
ProviderPlugin that talks to a platform's API (e.g. hashicorp/aws)
ResourceA piece of infrastructure to create (e.g. aws_s3_bucket)
Variable / OutputInputs to your config / values it exposes after apply
Data sourceRead-only lookup of existing resources
ModuleA reusable bundle of resources
StateTerraform's record of what it has created

The Terraform workflow

šŸ“· Insert image: terraform-workflow.png
  1. terraform init downloads the providers and prepares the backend.
  2. terraform plan compares your code with the real world and previews changes.
  3. terraform apply makes the changes and updates the state.
  4. terraform destroy removes everything it manages. Great for cleaning up labs.

Hands-on: an S3 bucket with Terraform

Create a file called main.tf:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}

provider "aws" {
region = "us-east-1"
}

resource "aws_s3_bucket" "demo" {
bucket = "my-iac-demo-bucket-12345" # must be globally unique

tags = {
Project = "iac-demo"
ManagedBy = "terraform"
}
}

resource "aws_s3_bucket_versioning" "demo" {
bucket = aws_s3_bucket.demo.id

versioning_configuration {
status = "Enabled"
}
}

output "bucket_name" {
value = aws_s3_bucket.demo.bucket
}
Make sure your AWS credentials are configured (for example with aws configure or IAM Identity Center), then run:
1
2
3
terraform init
terraform plan
terraform apply
The plan will end with something like Plan: 2 to add, 0 to change, 0 to destroy. Type yes and your bucket exists. When you're done experimenting:
1
terraform destroy
šŸ“· Optional: add a screenshot of your own terraform plan / apply output here. It makes the article more authentic.

Don't skip: remote state

By default Terraform stores state in a local terraform.tfstate file. That's fine for learning, but for teams you should store it remotely, in an S3 bucket with encryption and locking, so it's shared and protected from simultaneous runs:
1
2
3
4
5
6
7
8
9
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "demo/terraform.tfstate"
region = "us-east-1"
encrypt = true
use_lockfile = true
}
}
Older setups used a DynamoDB table for locking, so you'll still see that in many tutorials. Check the Terraform docs for the version you use. Never commit state files to Git, since they can contain sensitive values.

CloudFormation vs CDK vs Terraform

CloudFormationAWS CDKTerraform
LanguageYAML / JSONTypeScript, Python, Java, C#, GoHCL
Cloud supportAWS onlyAWS onlyMulti-cloud
StateManaged by AWSManaged by AWS (via CloudFormation)You manage it (e.g. S3)
Preview changesChange setscdk diffterraform plan
Best forAWS-only teams wanting zero setupDevelopers who prefer real codeMulti-cloud or portable skills
There's no single winner. If you're all-in on AWS, CloudFormation or CDK keep everything native. If you work across clouds, or want one skill that transfers, Terraform is a strong choice.

IaC best practices

  • Keep everything in Git and use pull requests for infrastructure changes.
  • Use remote state with encryption and locking.
  • Build modules instead of copy-pasting code.
  • Separate environments (dev / staging / prod), with separate state.
  • Follow least privilege for the IAM role your pipeline uses.
  • Never hardcode secrets. Use AWS Secrets Manager or SSM Parameter Store.
  • Run plan automatically in CI/CD and require review before apply.
  • Tag every resource so you can track ownership and cost.
  • Scan code with tools like cfn-lint, tfsec or Checkov before deploying.

Wrapping up

Infrastructure as Code turns cloud setup from a manual chore into something you can review, repeat and trust. Start small: pick one resource you normally create by hand, write it as code, and destroy and recreate it a couple of times. That's when it clicks.
Are you using CloudFormation, CDK or Terraform? Let me know in the comments, and what you'd like to see next, maybe a VPC or EC2 example or a CI/CD pipeline for Terraform. šŸš€
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article