CloudFormation’s DeletionPolicy doesn’t just prevent deletion; it dictates what happens to the underlying physical resource when its stack is deleted, not the CloudFormation resource itself.

Let’s see this in action. Imagine you have an S3 bucket managed by CloudFormation.

Resources:
  MyProtectedBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain # This is the key!
    Properties:
      BucketName: my-unique-protected-bucket-12345

When you deploy this stack and then try to delete it, CloudFormation will not delete the S3 bucket. It’s as if the bucket is now "orphaned" from the stack, but it still exists and is fully functional in your AWS account.

The DeletionPolicy is a property you set directly on a CloudFormation resource definition within your template. It has three possible values:

  • Retain: This is the most protective. When the stack is deleted, CloudFormation will not delete the physical resource. The resource will remain in your AWS account, independently of CloudFormation. This is ideal for critical resources like databases, S3 buckets containing important data, or load balancers that you don’t want accidentally removed.
  • Delete: This is the default behavior for most resources. When the stack is deleted, CloudFormation will delete the physical resource.
  • Snapshot: This applies only to specific resource types that support snapshotting, like RDS instances or EBS volumes. When the stack is deleted, CloudFormation will create a snapshot of the resource before deleting the resource itself. This gives you a point-in-time backup.

How it works under the hood:

When you set DeletionPolicy: Retain, CloudFormation essentially "detaches" the resource from its management lifecycle. It records that this resource was created by the stack, but it explicitly marks it as "do not touch" upon stack deletion. When the DeleteStack API call is made, CloudFormation iterates through the resources. For those with DeletionPolicy: Retain, it skips the deletion step. The resource continues to exist with its existing configuration, and you’ll need to manually delete it later if you no longer need it.

Consider an RDS instance:

Resources:
  MyProtectedDB:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Snapshot
    Properties:
      DBInstanceIdentifier: my-production-db
      DBInstanceClass: db.t3.medium
      Engine: postgres
      MasterUsername: admin
      MasterUserPassword: mysecurepassword
      AllocatedStorage: 20

Here, if you delete the stack, CloudFormation will trigger an RDS snapshot for my-production-db and then delete the instance. You’ll find the snapshot in your RDS console, and the instance will be gone. This is incredibly useful for production databases where you want a safety net, but don’t want the instance lingering if the stack is removed.

The one thing most people don’t know:

While DeletionPolicy is powerful, it doesn’t prevent you from deleting the physical resource directly through the AWS console or CLI. If you manually go to the RDS console and delete my-production-db, CloudFormation has no way of knowing or stopping that. The DeletionPolicy only governs CloudFormation’s actions during stack operations. If you want to truly protect a resource from any deletion, you’ll need to combine DeletionPolicy: Retain with IAM policies that restrict users from performing rds:DeleteDBInstance or s3:DeleteBucket actions, or perhaps use resource locks.

The next thing you’ll likely encounter is how to manage resources that aren’t directly managed by CloudFormation but are still associated with your stack, like DynamoDB tables created outside the stack but used by a Lambda function within it.

Want structured learning?

Take the full Cloudformation course →