CloudFormation’s update vs. replace behavior is often a source of confusion, but the core difference boils down to whether an update can be performed in-place or if the resource must be completely destroyed and recreated.
Let’s see this in action. Imagine you have an AWS::EC2::Instance resource defined in CloudFormation:
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0abcdef1234567890
InstanceType: t2.micro
Tags:
- Key: Name
Value: MyTestInstance
If you want to change the InstanceType from t2.micro to t3.micro, CloudFormation will replace the instance. The old instance will be terminated, and a new one will be launched with the updated configuration.
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0abcdef1234567890
InstanceType: t3.micro # Changed from t2.micro
Tags:
- Key: Name
Value: MyTestInstance
However, if you only change the Tags property, CloudFormation will perform an update in-place. The instance will continue running without interruption.
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0abcdef1234567890
InstanceType: t2.micro
Tags:
- Key: Name
Value: MyUpdatedTestInstance # Changed tag value
This distinction is critical because replacements lead to downtime for the resource and can affect other resources that depend on it. CloudFormation determines this behavior based on the underlying AWS API calls for each resource type and property. For EC2 instances, changing fundamental attributes like InstanceType, ImageId, or SubnetId requires replacement. Modifying less critical attributes like Tags or UserData can often be done in-place.
The mental model here is that CloudFormation acts as an orchestrator, translating your desired state into a series of AWS API calls. For some AWS resources, changing a property requires calling an API that effectively says "destroy this and create a new one with these parameters." For others, there’s an API that says "update this existing thing with these new parameters." CloudFormation inspects the changes you’ve made and consults its internal mapping of resource types and properties to these underlying API behaviors.
Consider an AWS::S3::Bucket resource. If you add a BucketPolicy to an existing bucket, CloudFormation will update the bucket in-place.
Resources:
MyS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-unique-bucket-name-12345
Tags:
- Key: Environment
Value: Production
# Adding a BucketPolicy
BucketPolicy:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: "*"
Action: "s3:GetObject"
Resource: !Sub "arn:aws:s3:::${MyS3Bucket}/*"
However, if you try to change the BucketName property, CloudFormation must replace the bucket. This is because bucket names are globally unique and immutable once created. CloudFormation will attempt to delete the old bucket and create a new one with the desired name. This is a destructive operation and will fail if the original bucket contains any objects.
The key to understanding this behavior is to remember that CloudFormation doesn’t magically change resources; it manages them. When a property change necessitates replacement, CloudFormation’s update process follows a specific, ordered sequence: it first creates the new resource with the updated properties, then updates any dependent resources to point to the new resource, and finally deletes the old resource. This ensures that the application remains available during the update as much as possible, by having both the old and new versions coexist briefly.
A common point of confusion arises when a resource update appears to be in-place but actually involves a replacement that CloudFormation handles gracefully. For example, updating the AutoScalingGroupName within an AWS::AutoScaling::AutoScalingGroup resource will trigger a replacement of the Auto Scaling group itself. CloudFormation will launch a new group with the specified name and configuration and then terminate the old one. The instances within the group might be terminated and replaced according to the Auto Scaling group’s policies, but the group resource itself is replaced. This is a subtle but important distinction – the lifecycle of the group is distinct from the lifecycle of the instances it manages.
Ultimately, the decision of whether a change triggers an update or a replacement is determined by the AWS service’s API capabilities for that specific resource type and property. CloudFormation’s documentation for each resource type will explicitly state which properties, when modified, cause a replacement. It’s always a good practice to consult this documentation before making changes to critical infrastructure.
The next thing you’ll likely run into is how to handle resources that cannot be updated in-place, like changing the BucketName of an S3 bucket with existing objects, and the strategies CloudFormation employs to manage these disruptive changes.