All topics
Cloud · Learning hub

CloudFormation notes for developers

Master CloudFormation with a curated set of 2 developer notes — core concepts, patterns, and interview prep. Maintained by the DevRecall team.

Save this stack to your DevRecallMore Cloud notes
CloudFormation

Templates, Resources & Parameters

CloudFormation: Templates, Resources & Parameters AWS CloudFormation lets you model and provision AWS infrastructure using YAML or JSON templates. A template de

CloudFormation: Templates, Resources & Parameters

AWS CloudFormation lets you model and provision AWS infrastructure using YAML or JSON templates. A template defines the desired state; CloudFormation handles create/update/delete in the right order based on dependencies.

Template Structure

AWSTemplateFormatVersion: '2010-09-09'
Description: 'My Application Stack'

# Metadata (optional — controls console display)
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label: { default: "Network Configuration" }
        Parameters: [VpcId, SubnetId]

# Parameters — inputs (override at deploy time)
Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues: [dev, staging, prod]
    Description: Deployment environment

  InstanceType:
    Type: String
    Default: t3.micro
    AllowedValues: [t3.micro, t3.small, t3.medium]

  DbPassword:
    Type: String
    NoEcho: true     # hides value in console/CLI output
    MinLength: 8

# Mappings — lookup table by key
Mappings:
  RegionAMI:
    us-east-1:
      AMI: ami-0c02fb55956c7d316
    eu-west-1:
      AMI: ami-0d71ea30463e0ff49

# Conditions
Conditions:
  IsProduction: !Equals [!Ref Environment, prod]
  CreateProdResources: !And
    - !Condition IsProduction
    - !Not [!Equals [!Ref InstanceType, t3.micro]]

# Resources — required, the actual infrastructure
Resources:
  MyBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub 'my-app-${Environment}-${AWS::AccountId}'
      VersioningConfiguration:
        Status: Enabled
      Tags:
        - Key: Environment
          Value: !Ref Environment

# Outputs — values to expose after stack creation
Outputs:
  BucketName:
    Description: Name of the S3 bucket
    Value: !Ref MyBucket
    Export:
      Name: !Sub '${AWS::StackName}-BucketName'   # for cross-stack references

Common Resource Types

Resources:

  # EC2 Instance
  WebServer:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !FindInMap [RegionAMI, !Ref AWS::Region, AMI]
      KeyName: my-keypair
      SecurityGroupIds: [!Ref WebSG]
      SubnetId: !Ref PublicSubnet
      UserData:
        Fn::Base64: |
          #!/bin/bash
          yum update -y
          yum install -y httpd
          systemctl start httpd
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-WebServer'

  # Security Group
  WebSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Web server security group
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0

  # RDS
  Database:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Snapshot          # take snapshot on stack delete
    Properties:
      DBInstanceClass: db.t3.micro
      Engine: postgres
      EngineVersion: '15.4'
      MasterUsername: admin
      MasterUserPassword: !Ref DbPassword
      AllocatedStorage: 20
      StorageType: gp3
      MultiAZ: !If [IsProduction, true, false]
      DeletionProtection: !If [IsProduction, true, false]

  # Lambda
  ProcessorFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub '${AWS::StackName}-processor'
      Runtime: python3.12
      Handler: index.handler
      Role: !GetAtt LambdaRole.Arn
      Code:
        ZipFile: |
          def handler(event, context):
              return {'statusCode': 200}
      Environment:
        Variables:
          ENV: !Ref Environment
          TABLE_NAME: !Ref DynamoTable
CloudFormation

Stacks, Changesets, Intrinsic Functions & Best Practices

CloudFormation: Stacks, Changesets & Best Practices CLI: Stack Operations # Deploy stack aws cloudformation deploy --template-file template.yaml --stack-name my

CloudFormation: Stacks, Changesets & Best Practices

CLI: Stack Operations

# Deploy stack
aws cloudformation deploy   --template-file template.yaml   --stack-name my-app-dev   --parameter-overrides Environment=dev DbPassword=secret123   --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM   --region us-east-1

# Create stack (alternative — more control)
aws cloudformation create-stack   --stack-name my-app   --template-body file://template.yaml   --parameters ParameterKey=Environment,ParameterValue=dev   --capabilities CAPABILITY_IAM

# Update stack
aws cloudformation update-stack   --stack-name my-app   --template-body file://template.yaml   --parameters ParameterKey=Environment,ParameterValue=prod

# Wait for completion
aws cloudformation wait stack-create-complete --stack-name my-app
aws cloudformation wait stack-update-complete --stack-name my-app

# Describe stack
aws cloudformation describe-stacks --stack-name my-app
aws cloudformation describe-stack-events --stack-name my-app

# Delete stack
aws cloudformation delete-stack --stack-name my-app
aws cloudformation wait stack-delete-complete --stack-name my-app

# Validate template
aws cloudformation validate-template --template-body file://template.yaml

Changesets

Changesets let you preview what CloudFormation will do before executing. Always use changesets for production updates.

# Create changeset (preview changes)
aws cloudformation create-change-set   --stack-name my-app   --template-body file://template.yaml   --change-set-name my-update-$(date +%Y%m%d)   --parameters ParameterKey=InstanceType,ParameterValue=t3.small

# View changeset (what will be added/modified/removed)
aws cloudformation describe-change-set   --stack-name my-app   --change-set-name my-update-20240315

# Execute changeset
aws cloudformation execute-change-set   --stack-name my-app   --change-set-name my-update-20240315

# Delete changeset (if you decide not to apply)
aws cloudformation delete-change-set   --stack-name my-app   --change-set-name my-update-20240315

Intrinsic Functions

# !Ref — reference a parameter or resource
VpcId: !Ref MyVPC

# !Sub — string substitution
Name: !Sub '${AWS::StackName}-web-${Environment}'
# AWS pseudo-parameters: AWS::AccountId, AWS::Region, AWS::StackName, AWS::NoValue

# !GetAtt — get attribute of a resource
RoleArn: !GetAtt MyRole.Arn
BucketDomainName: !GetAtt MyBucket.DomainName

# !FindInMap — lookup in Mappings
ImageId: !FindInMap [RegionAMI, !Ref AWS::Region, AMI]

# !Select — pick item from list
AZ: !Select [0, !GetAZs '']  # first AZ in region

# !Split — split string to list
Parts: !Split [',', 'a,b,c']

# !Join — join list to string
BucketName: !Join ['-', [!Ref AWS::StackName, !Ref Environment, 'data']]

# !If — conditional value
MultiAZ: !If [IsProduction, true, false]
OptionalResource:
  Type: AWS::S3::Bucket
  Condition: IsProduction   # only create if condition is true

# !ImportValue — cross-stack reference
VpcId: !ImportValue 'network-stack-VpcId'

# !Base64 — encode for UserData
UserData: !Base64 |
  #!/bin/bash
  echo "Hello" > /tmp/test.txt

Best Practices

  • Use changeset review for all production updates — never update-stack directly in prod.

  • Set DeletionPolicy: Retain or Snapshot on stateful resources (RDS, S3) to prevent accidental loss.

  • Use nested stacks to split large templates: AWS::CloudFormation::Stack with TemplateURL.

  • Use StackSets to deploy the same template across multiple accounts and regions simultaneously.

  • Store sensitive parameters in AWS Secrets Manager or SSM Parameter Store (SecureString), not template Parameters.

  • Tag all resources consistently: add a Tags section to every resource for cost allocation and filtering.

  • Use cfn-lint (CloudFormation Linter) in CI to catch errors before deployment.

  • Prefer CDK or SAM for complex applications — they generate CloudFormation but with better abstractions.

Keep your CloudFormation knowledge sharp.

Save this stack to your personal DevRecall — add your own notes, track what you're learning, and share what you know with the community.

Get started — free forever