Home DevOps AWS CloudFormation: Infrastructure as Code
Intermediate 5 min · July 12, 2026

AWS CloudFormation: Infrastructure as Code

A comprehensive guide to AWS CloudFormation: Infrastructure as Code on AWS, covering core concepts, configuration, best practices, and real-world use cases..

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Everything here is grounded in real deployments.

Follow
Verified
production tested
July 12, 2026
last updated
2,073
articles · all by Naren
Before you start⏱ 25 min
  • Basic understanding of AWS services and cloud computing concepts.
✦ Definition~90s read
What is AWS CloudFormation?

AWS CloudFormation is an Infrastructure as Code (IaC) service that lets you define and provision AWS resources using declarative templates. It matters because it enables repeatable, version-controlled infrastructure deployments, reducing manual errors and drift. Use it when you need to manage complex AWS environments consistently across multiple stages or accounts.

AWS CloudFormation: Infrastructure as Code is like having a smart assistant that handles the heavy lifting so you don't have to manage servers yourself.
Plain-English First

AWS CloudFormation: Infrastructure as Code is like having a smart assistant that handles the heavy lifting so you don't have to manage servers yourself.

⚙ Browser compatibility
Latest versions — ✓ supported
ChromeFirefoxSafariEdge

You've been manually clicking through the AWS console for months. Your staging environment is a snowflake—slightly different from production, and nobody knows why. Then a critical security group rule gets deleted during a late-night fix, and your database is exposed. This is the reality without Infrastructure as Code. CloudFormation forces you to declare your entire infrastructure in a JSON or YAML template, then handles the provisioning and updates. It's not the only IaC tool (Terraform exists), but it's native to AWS, deeply integrated, and free. The trade-off? You're locked into AWS, and the template syntax can be verbose. But for teams already all-in on AWS, CloudFormation provides a single source of truth for your infrastructure, with built-in rollback and drift detection. Stop treating your infrastructure like a pet—start treating it like cattle.

Why CloudFormation? The Case for Declarative Infrastructure

CloudFormation is AWS's native Infrastructure as Code (IaC) service. Unlike imperative tools (e.g., scripts), you declare your desired state in a template, and CloudFormation handles the provisioning, updates, and deletions. This eliminates drift, enables version control, and provides a single source of truth. In production, the biggest win is repeatability: you can spin up identical environments for dev, staging, and prod without manual clicks. The downside? Learning curve and verbose YAML/JSON. But once you internalize the resource model, you'll never go back to manual console work. CloudFormation also integrates with AWS services like IAM, Lambda, and CodePipeline, making it the backbone of many enterprise deployments.

basic-vpc.yamlYAML
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
AWSTemplateFormatVersion: '2010-09-09'
Description: A simple VPC with a single public subnet

Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: MyVPC

  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: PublicSubnet

Outputs:
  VpcId:
    Description: VPC ID
    Value: !Ref MyVPC
  SubnetId:
    Description: Subnet ID
    Value: !Ref PublicSubnet
Output
Stack creation successful. Outputs:
VpcId: vpc-0a1b2c3d4e5f6g7h8
SubnetId: subnet-12345678
🔥Template Format
CloudFormation templates can be YAML or JSON. YAML is preferred for readability. Always include AWSTemplateFormatVersion to future-proof your templates.
📊 Production Insight
In production, always use Change Sets before updating stacks to preview changes and avoid accidental resource replacements.
🎯 Key Takeaway
CloudFormation lets you define infrastructure as code, enabling repeatable, version-controlled deployments.
aws-cloudformation-iac THECODEFORGE.IO CloudFormation Template Deployment Flow Step-by-step process from template creation to stack deployment Write Template Define resources, parameters, and outputs in YAML/JSON Validate Template Use cfn-lint or ValidateTemplate API to check syntax Create Stack Submit template to CloudFormation service Provision Resources CloudFormation creates resources in dependency order Monitor Progress Track stack events and rollback on failure Verify Outputs Retrieve stack outputs for downstream use ⚠ Forgetting DependsOn can cause race conditions Explicitly declare dependencies for non-default ordering THECODEFORGE.IO
thecodeforge.io
Aws Cloudformation Iac

Template Anatomy: Resources, Parameters, and Outputs

Every CloudFormation template has three main sections: Resources (mandatory), Parameters (optional), and Outputs (optional). Resources define the AWS components (EC2, S3, etc.). Parameters allow you to pass values at stack creation, like instance types or environment names. Outputs return useful information after stack creation, such as resource IDs or endpoints. A common mistake is hardcoding values instead of using Parameters. Always parameterize anything that varies between environments. Also, use intrinsic functions like !Ref and !GetAtt to reference other resources. This creates a dependency graph that CloudFormation uses to determine creation order. For example, a security group that references a VPC must be created after the VPC.

parameterized-vpc.yamlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC with parameterized CIDR

Parameters:
  VpcCIDR:
    Description: CIDR block for the VPC
    Type: String
    Default: 10.0.0.0/16
    AllowedPattern: "(\\d{1,3}\\.){3}\\d{1,3}/\\d{1,2}"

Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true

Outputs:
  VpcId:
    Description: VPC ID
    Value: !Ref MyVPC
Output
Stack created with VpcCIDR=10.0.0.0/16. VpcId: vpc-0a1b2c3d4e5f6g7h8
💡Parameter Constraints
Use AllowedPattern, AllowedValues, and MinLength/MaxLength to validate parameter inputs. This prevents misconfigurations early.
📊 Production Insight
Never hardcode sensitive values like passwords. Use AWS Secrets Manager or SSM Parameter Store with dynamic references (resolve-secrets-manager).
🎯 Key Takeaway
Parameters make templates reusable; Outputs expose important resource attributes for cross-stack references.

Intrinsic Functions: The Glue That Holds Templates Together

Intrinsic functions are built-in CloudFormation functions that let you assign values dynamically. The most common are !Ref (returns the physical ID of a resource), !GetAtt (returns an attribute), !Join (concatenates strings), !Select (picks from a list), and !Sub (string substitution with variables). These functions are evaluated during stack operations, not at template authoring time. For example, !Sub '${AWS::StackName}-bucket' creates a bucket name based on the stack name. Another critical function is !If, which enables conditional resource creation based on a condition. Mastering these functions reduces duplication and makes templates more flexible. However, overusing nested functions can make templates hard to read. Keep it simple.

functions-demo.yamlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
AWSTemplateFormatVersion: '2010-09-09'
Description: Demonstrating intrinsic functions

Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, prod]

Conditions:
  IsProd: !Equals [!Ref Environment, prod]

Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub '${AWS::StackName}-${Environment}-bucket'
      VersioningConfiguration:
        Status: !If [IsProd, Enabled, Suspended]

Outputs:
  BucketName:
    Value: !Ref Bucket
  BucketArn:
    Value: !GetAtt Bucket.Arn
Output
Stack created with Environment=dev. Bucket name: functions-demo-dev-bucket. Versioning: Suspended.
⚠ Function Evaluation Order
Intrinsic functions are evaluated after resource creation. You cannot use !GetAtt on a resource that hasn't been created yet. CloudFormation handles dependencies, but be careful with circular dependencies.
📊 Production Insight
Use !Sub with AWS pseudo parameters (AWS::Region, AWS::AccountId) to create globally unique resource names and avoid naming collisions.
🎯 Key Takeaway
Intrinsic functions like !Ref, !GetAtt, and !Sub enable dynamic, context-aware templates.
aws-cloudformation-iac THECODEFORGE.IO CloudFormation Template Architecture Layers Hierarchical structure of a CloudFormation template Metadata TemplateDescription | AWS::CloudFormation::Interface Parameters InstanceType | KeyName | VpcId Conditions IsProduction | UseEncryption Resources EC2 Instance | Security Group | S3 Bucket Outputs InstanceId | BucketArn | EndpointURL THECODEFORGE.IO
thecodeforge.io
Aws Cloudformation Iac

Managing Dependencies with DependsOn and Resource Attributes

CloudFormation automatically determines resource creation order based on references (e.g., !Ref, !GetAtt). However, sometimes you need explicit ordering, especially when a resource depends on a side effect (like a Lambda function that creates a database schema). Use the DependsOn attribute to force a dependency. Another common pattern is using the CreationPolicy or UpdatePolicy to wait for signals from EC2 instances or Lambda functions before marking a resource as created. For example, you can configure an Auto Scaling group to wait for a signal from a bootstrap script. Without these, your stack might report success before the application is ready, causing downstream failures. Always test dependency chains in a sandbox first.

depends-on.yamlYAML
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
AWSTemplateFormatVersion: '2010-09-09'
Description: Demonstrating DependsOn

Resources:
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow SSH
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0

  EC2Instance:
    Type: AWS::EC2::Instance
    DependsOn: SecurityGroup
    Properties:
      ImageId: ami-0abcdef1234567890
      InstanceType: t2.micro
      SecurityGroups:
        - !Ref SecurityGroup
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          yum install -y httpd
          systemctl start httpd
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region}
    CreationPolicy:
      ResourceSignal:
        Timeout: PT5M
        Count: 1
Output
Stack creation waits up to 5 minutes for the EC2 instance to signal success. If signal not received, stack creation fails.
💡Avoid Unnecessary DependsOn
Only use DependsOn when CloudFormation cannot infer the dependency. Overusing it can slow down stack operations and make templates brittle.
📊 Production Insight
In production, always set CreationPolicy with a reasonable timeout. Without it, a misconfigured instance can cause silent failures that are hard to debug.
🎯 Key Takeaway
Use DependsOn for explicit ordering and CreationPolicy to wait for application readiness.

Stack Updates: Change Sets, Drift Detection, and Rollbacks

Updating a CloudFormation stack is where most production issues arise. Always use Change Sets to preview what will change before applying. Change Sets show you which resources will be added, modified, or replaced. Replacement is dangerous: it destroys the old resource and creates a new one (e.g., an EC2 instance with a new private IP). To avoid data loss, use DeletionPolicy: Retain on critical resources like databases. Drift detection compares the actual resource configuration against the template. If someone manually changes a resource (e.g., modifies a security group rule), drift detection flags it. Run drift detection regularly. Finally, configure rollback triggers: if a stack update fails, CloudFormation can automatically roll back to the previous state. But beware: rollbacks can also fail, leaving your stack in a partial state.

change-set-commands.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Create a change set
aws cloudformation create-change-set \
  --stack-name my-stack \
  --template-body file://updated-template.yaml \
  --change-set-name my-change-set

# Describe the change set
aws cloudformation describe-change-set \
  --stack-name my-stack \
  --change-set-name my-change-set

# Execute the change set
aws cloudformation execute-change-set \
  --stack-name my-stack \
  --change-set-name my-change-set
Output
Change set shows: Modify VPC (no interruption), Replace EC2Instance (replacement), Add SecurityGroup (no interruption).
⚠ Rollback Failure
If a stack update fails and rollback also fails, your stack enters ROLLBACK_FAILED state. You may need to manually fix resources or delete the stack. Always test updates in a non-production environment.
📊 Production Insight
Set DeletionPolicy: Retain on RDS databases and EBS volumes. Otherwise, a stack deletion can wipe out production data.
🎯 Key Takeaway
Always use Change Sets before updates, enable drift detection, and configure rollback triggers to minimize production impact.

Nested Stacks and Cross-Stack References

As your infrastructure grows, a single template becomes unwieldy. Nested stacks allow you to compose multiple templates into a hierarchy. For example, a parent stack can reference a child stack that creates a VPC, and another child that creates EC2 instances. This promotes reusability and separation of concerns. However, nested stacks have limitations: you cannot reference outputs from a sibling stack directly; you must pass them through the parent. Cross-stack references using Export and Import functions allow stacks in the same account and region to share resources. For example, a network stack exports the VPC ID, and an application stack imports it. This decouples stacks but creates implicit dependencies. Be careful: if you delete a stack that exports a value, any stack importing it will fail.

parent-stack.yamlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
AWSTemplateFormatVersion: '2010-09-09'
Description: Parent stack with nested stacks

Resources:
  NetworkStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://s3.amazonaws.com/my-bucket/network.yaml
      Parameters:
        VpcCIDR: 10.0.0.0/16

  AppStack:
    Type: AWS::CloudFormation::Stack
    DependsOn: NetworkStack
    Properties:
      TemplateURL: https://s3.amazonaws.com/my-bucket/app.yaml
      Parameters:
        VpcId: !GetAtt NetworkStack.Outputs.VpcId
        SubnetId: !GetAtt NetworkStack.Outputs.SubnetId
Output
Parent stack creates two nested stacks. NetworkStack outputs VpcId and SubnetId, which are passed to AppStack.
🔥Nested Stack Limits
You can nest up to 200 stacks deep. Each nested stack has its own set of resources and outputs. Use AWS::CloudFormation::Interface to organize parameters.
📊 Production Insight
Store nested stack templates in an S3 bucket with versioning enabled. This allows you to roll back to a previous template version if needed.
🎯 Key Takeaway
Nested stacks and cross-stack references enable modular, reusable infrastructure while managing dependencies.

Custom Resources: Extending CloudFormation with Lambda

Sometimes you need to provision resources that CloudFormation doesn't natively support (e.g., a DNS record in Route53 outside your account, or a configuration in a third-party service). Custom resources let you invoke a Lambda function during stack create, update, and delete. The Lambda function receives a request with properties and must return a response indicating success or failure. This is powerful but error-prone. Common pitfalls: the Lambda function must send a response within 1 hour (default timeout), and if it fails, the stack operation hangs until timeout. Always implement idempotency: the same request should produce the same result. Also, handle stack deletion properly — your Lambda should clean up resources. Use the cfn-response module or the aws-cloudformation-custom-resource helper.

custom-resource-lambda.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import boto3
import cfnresponse

def handler(event, context):
    physical_resource_id = event.get('PhysicalResourceId', 'initial')
    try:
        if event['RequestType'] == 'Create':
            # Create resource
            physical_resource_id = 'my-resource-id'
            # Send success
            cfnresponse.send(event, context, cfnresponse.SUCCESS, {'ResourceId': physical_resource_id}, physical_resource_id)
        elif event['RequestType'] == 'Update':
            # Update resource
            cfnresponse.send(event, context, cfnresponse.SUCCESS, {'ResourceId': physical_resource_id}, physical_resource_id)
        elif event['RequestType'] == 'Delete':
            # Delete resource
            cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, physical_resource_id)
    except Exception as e:
        cfnresponse.send(event, context, cfnresponse.FAILED, {'Message': str(e)}, physical_resource_id)
Output
Lambda function invoked during stack creation. Returns success with ResourceId. Stack creation proceeds.
⚠ Lambda Timeout
Custom resource Lambda must respond within the function timeout (max 15 minutes). If it doesn't, CloudFormation waits for 1 hour then fails the stack operation. Set a reasonable timeout.
📊 Production Insight
Always implement idempotency and handle deletion. A common failure is forgetting to clean up resources on stack deletion, leading to orphaned resources.
🎯 Key Takeaway
Custom resources allow you to manage non-AWS resources or complex provisioning logic via Lambda functions.

StackSets: Multi-Account and Multi-Region Deployments

Managing infrastructure across multiple AWS accounts and regions is a challenge. StackSets allow you to deploy CloudFormation stacks across accounts and regions from a single template. You define a StackSet with target accounts and regions, and CloudFormation creates stack instances in each. This is ideal for governance (e.g., enabling AWS Config rules in all accounts) or deploying a standard VPC baseline. However, StackSets have limitations: they don't support nested stacks, and updates can be slow for large deployments. Also, if a stack instance fails, the entire operation can be affected. Use StackSets with service-managed permissions (using AWS Organizations) to automatically deploy to new accounts. Always test in a limited set of accounts first.

create-stackset.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
# Create a StackSet
aws cloudformation create-stack-set \
  --stack-set-name my-stackset \
  --template-body file://template.yaml \
  --capabilities CAPABILITY_IAM

# Add stack instances
aws cloudformation create-stack-instances \
  --stack-set-name my-stackset \
  --accounts '123456789012' '210987654321' \
  --regions 'us-east-1' 'eu-west-1' \
  --operation-preferences FailureToleranceCount=0,MaxConcurrentCount=2
Output
StackSet created. Stack instances being created in 2 accounts x 2 regions = 4 stacks. Progress: 2/4 complete.
🔥StackSet Permissions
You need IAM roles in the target accounts that allow CloudFormation to create resources. Use service-managed permissions with AWS Organizations for automatic trust setup.
📊 Production Insight
Set FailureToleranceCount to 0 to stop on first failure. Otherwise, partial failures can leave your accounts in inconsistent states.
🎯 Key Takeaway
StackSets enable consistent infrastructure deployment across multiple accounts and regions from a single template.

CI/CD Integration: Automating CloudFormation Deployments

Manual stack operations are error-prone. Integrate CloudFormation with a CI/CD pipeline (e.g., AWS CodePipeline, Jenkins, GitHub Actions) to automate deployments. The pipeline should: (1) validate templates using cfn-lint or aws cloudformation validate-template, (2) create a change set, (3) require manual approval for production, (4) execute the change set, and (5) run drift detection after deployment. Use Git as the source of truth; any change to the template should trigger the pipeline. A common pattern is to have separate pipelines for different environments. Also, use stack policies to prevent accidental updates to critical resources. For example, you can deny updates to a production database. Automating deployments reduces human error and enforces compliance.

buildspec.yamlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: 0.2

phases:
  install:
    runtime-versions:
      python: 3.8
    commands:
      - pip install cfn-lint
  pre_build:
    commands:
      - cfn-lint template.yaml
      - aws cloudformation validate-template --template-body file://template.yaml
  build:
    commands:
      - aws cloudformation create-change-set --stack-name my-stack --template-body file://template.yaml --change-set-name my-change-set --capabilities CAPABILITY_IAM
      - aws cloudformation describe-change-set --stack-name my-stack --change-set-name my-change-set
  post_build:
    commands:
      - echo "Manual approval required before executing change set"
artifacts:
  files:
    - template.yaml
Output
Build succeeds. Change set created. Waiting for manual approval to execute.
💡Template Validation
Always run cfn-lint and validate-template in your CI pipeline. This catches syntax errors and best practice violations before deployment.
📊 Production Insight
Use stack policies to protect critical resources. For example, deny updates to production databases to prevent accidental deletion or modification.
🎯 Key Takeaway
Automate CloudFormation deployments with CI/CD pipelines that include validation, change sets, and approval gates.

Troubleshooting Common CloudFormation Failures

Even with best practices, CloudFormation stacks fail. Common failures include: (1) Insufficient IAM permissions — the role executing the stack doesn't have permissions to create resources. (2) Resource limits — hitting AWS service limits (e.g., VPC limit per region). (3) Circular dependencies — two resources depend on each other. (4) Invalid properties — misspelled property names or wrong types. (5) Timeouts — resources taking too long to create (e.g., RDS instance). To debug, check the stack events in the CloudFormation console or CLI. The error message usually points to the failing resource. Use DescribeStackEvents to get detailed error messages. For Lambda-backed custom resources, check CloudWatch Logs. Also, enable termination protection on production stacks to prevent accidental deletion.

debug-stack.shBASH
1
2
3
4
5
6
7
8
# Describe stack events
aws cloudformation describe-stack-events --stack-name my-stack --query "StackEvents[?ResourceStatus=='CREATE_FAILED']"

# Get the physical resource ID of the failed resource
aws cloudformation describe-stack-resources --stack-name my-stack --query "StackResources[?ResourceStatus=='CREATE_FAILED'].PhysicalResourceId"

# Check CloudWatch Logs for custom resource Lambda
aws logs filter-log-events --log-group-name /aws/lambda/my-custom-resource --filter-pattern "ERROR"
Output
Stack event shows: 'Resource creation cancelled' for EC2Instance. Error: 'You have reached the maximum number of EC2 instances in this region.'
⚠ Termination Protection
Enable termination protection on production stacks. Without it, anyone with delete permissions can accidentally delete the entire stack and all resources.
📊 Production Insight
Set up CloudWatch alarms on stack events (e.g., stack creation failure) to alert the team immediately. Proactive monitoring reduces downtime.
🎯 Key Takeaway
Debug stack failures by examining stack events, resource statuses, and CloudWatch Logs for custom resources.

Production Best Practices: Security, Cost, and Governance

In production, CloudFormation templates must enforce security and cost controls. Use IAM roles with least privilege for stack operations. Never hardcode secrets; use dynamic references to Secrets Manager or SSM Parameter Store. For cost governance, tag all resources with cost centers and use AWS Budgets to monitor spending. Implement stack policies to prevent updates to critical resources. Use AWS Config rules to enforce compliance (e.g., require encryption on S3 buckets). Also, regularly run drift detection and review stack events. Finally, use the AWS CloudFormation Registry to discover third-party resource types. But be cautious: third-party resources may have different stability guarantees. Always test in a non-production environment first.

production-stack-policy.jsonYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  "Statement": [
    {
      "Effect": "Deny",
      "Action": [
        "Update:Replace",
        "Update:Delete"
      ],
      "Principal": "*",
      "Resource": "LogicalResourceId/ProductionDatabase"
    },
    {
      "Effect": "Allow",
      "Action": "Update:*",
      "Principal": "*",
      "Resource": "*"
    }
  ]
}
Output
Stack policy applied. Attempts to replace or delete ProductionDatabase will be denied.
🔥Resource Tags
Tag all resources with Environment, CostCenter, and Owner. This enables cost allocation and simplifies resource identification.
📊 Production Insight
Use AWS Config to automatically remediate non-compliant resources. For example, automatically enable encryption on S3 buckets that are created without it.
🎯 Key Takeaway
Enforce security, cost, and governance through IAM roles, stack policies, tagging, and dynamic references for secrets.
CloudFormation vs Terraform: IaC Approaches Comparing declarative infrastructure tools for AWS CloudFormation Terraform Language YAML or JSON templates HashiCorp Configuration Language (HCL) State Management Managed by AWS automatically State file stored locally or remotely Multi-Cloud Support AWS only Supports AWS, Azure, GCP, and more Drift Detection Built-in drift detection via API Requires manual `terraform plan` compari Rollback Behavior Automatic rollback on failure Manual rollback via state manipulation THECODEFORGE.IO
thecodeforge.io
Aws Cloudformation Iac

The Future: CloudFormation vs. CDK and Terraform

CloudFormation is mature but has competition. AWS CDK allows you to define infrastructure in familiar programming languages (TypeScript, Python, etc.) and synthesizes CloudFormation templates. This gives you the power of programming (loops, conditionals) with the safety of CloudFormation. Terraform is multi-cloud and has a larger community, but it's not AWS-native. For AWS-only shops, CloudFormation (or CDK) is often the best choice because of deep integration and first-class support. However, CDK's abstraction can hide complexity, leading to unexpected resource configurations. Terraform's state management is different and can cause drift. My opinion: if you're all-in on AWS, use CDK for complex logic and CloudFormation for simple templates. If you need multi-cloud, use Terraform. But whatever you choose, IaC is non-negotiable.

cdk-stack.tsTYPESCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

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

    const vpc = new ec2.Vpc(this, 'MyVpc', {
      maxAzs: 2,
      subnetConfiguration: [
        { name: 'public', subnetType: ec2.SubnetType.PUBLIC },
      ],
    });

    new cdk.CfnOutput(this, 'VpcId', { value: vpc.vpcId });
  }
}

const app = new cdk.App();
new MyStack(app, 'MyStack');
Output
CDK synthesizes a CloudFormation template and deploys it. Output: VpcId.
Try it live
🔥CDK Best Practice
Always run cdk diff before deploying to see what changes will be made. This is analogous to CloudFormation Change Sets.
📊 Production Insight
Regardless of tool, always review the generated CloudFormation template from CDK. Abstractions can hide expensive or insecure configurations.
🎯 Key Takeaway
Choose CloudFormation for simplicity, CDK for programmability, and Terraform for multi-cloud. IaC is mandatory for production.
⚙ Quick Reference
12 commands from this guide
FileCommand / CodePurpose
basic-vpc.yamlAWSTemplateFormatVersion: '2010-09-09'Why CloudFormation? The Case for Declarative Infrastructure
parameterized-vpc.yamlAWSTemplateFormatVersion: '2010-09-09'Template Anatomy
functions-demo.yamlAWSTemplateFormatVersion: '2010-09-09'Intrinsic Functions
depends-on.yamlAWSTemplateFormatVersion: '2010-09-09'Managing Dependencies with DependsOn and Resource Attributes
change-set-commands.shaws cloudformation create-change-set \Stack Updates
parent-stack.yamlAWSTemplateFormatVersion: '2010-09-09'Nested Stacks and Cross-Stack References
custom-resource-lambda.pydef handler(event, context):Custom Resources
create-stackset.shaws cloudformation create-stack-set \StackSets
buildspec.yamlversion: 0.2CI/CD Integration
debug-stack.shaws cloudformation describe-stack-events --stack-name my-stack --query "StackEve...Troubleshooting Common CloudFormation Failures
production-stack-policy.json{Production Best Practices
cdk-stack.tsexport class MyStack extends cdk.Stack {The Future

Key takeaways

1
Declarative Infrastructure
Define your entire AWS environment in a single template. No more manual configuration or snowflake servers.
2
Change Sets and Rollbacks
Preview changes before applying them. If an update fails, CloudFormation automatically rolls back to the last known good state.
3
Drift Detection
Regularly check if your actual infrastructure matches the template. This catches manual changes that break your IaC model.
4
Nested Stacks and Modules
Break large templates into reusable components. Use nested stacks or the AWS Serverless Application Model (SAM) for microservices.

Common mistakes to avoid

2 patterns
×

Overlooking aws cloudformation iac basic configuration

Symptom
Unexpected behavior in production
Fix
Follow AWS best practices and review documentation thoroughly
×

Ignoring cost implications

Symptom
Unexpected AWS bill at end of month
Fix
Set up billing alerts and use cost explorer to monitor usage
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is AWS CloudFormation: Infrastructure as Code and when would you us...
Q02SENIOR
How do you secure AWS CloudFormation: Infrastructure as Code in producti...
Q03SENIOR
What are the cost optimization strategies for AWS CloudFormation: Infras...
Q01 of 03JUNIOR

What is AWS CloudFormation: Infrastructure as Code and when would you use it?

ANSWER
AWS CloudFormation: Infrastructure as Code is an AWS service that helps manage cloud infrastructure efficiently. Use it when you need scalable, reliable cloud solutions.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
What's the difference between CloudFormation and Terraform?
02
How do I handle secrets in CloudFormation templates?
03
What is a stack and a stack set?
04
How do I update a stack without downtime?
05
What is drift detection and why should I care?
06
Can I use CloudFormation with CI/CD pipelines?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Everything here is grounded in real deployments.

Follow
Verified
production tested
July 12, 2026
last updated
2,073
articles · all by Naren
🔥

That's AWS. Mark it forged?

5 min read · try the examples if you haven't

Previous
Elastic Load Balancing: ALB, NLB, and Gateway Load Balancer
22 / 54 · AWS
Next
Amazon ElastiCache: Redis and Memcached In-Memory Caching