AWS CDK Removing automatic cross-stack references
- Published on
- Authors
- Name
- Binh Bui
- @bvbinh
Photo by Ozkan Guner
Removing automatic cross-stack references
What is automatic cross-stack references?
The automatic references created by CDK when you use resources across stacks are convenient, but may block your deployments if you want to remove the resources that are referenced in this way. You will see an error like:
Export Stack1:ExportsOutputFnGetAtt-****** cannot be deleted as it is in use by Stack1
Let's say there is a Bucket in the stack1, and the stack2 references its bucket.bucketName. You see full demo code in the GitHub repository
export class Stack1 extends Stack {
readonly bucket: s3.Bucket
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props)
// Let's say there is a Bucket in the stack1, and the stack2 references its bucket.bucketName.
const bucket = new s3.Bucket(this, 'bucket', {
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
})
this.bucket = bucket
}
}
export class Stack2 extends Stack {
constructor(scope: Construct, id: string, props: Stack2Props) {
super(scope, id, props)
// comment out the following line and re-deploy to see the error
// ❌ Stack1 failed: Error: The stack named Stack1 failed to deploy: UPDATE_ROLLBACK_COMPLETE
new CfnOutput(this, 'bucketName', {
value: props.bucket.bucketName,
})
}
}
npx cdk deploy --all
Deploy all stacks by running You now want to remove the bucket due to not using any more. It's not safe to remove stack1.bucket while stack2 is still using it. To reproduce this, You can remove all references to stack1.bucket then re-deploy by running npx cdk deploy --all
. It will show the following error:
❌ Stack1 failed: Error: The stack named Stack1 failed to deploy: UPDATE_ROLLBACK_COMPLETE
So unblocking yourself from this is a two-step process. This is how it works:
DEPLOYMENT 1: break the relationship
- Make sure stack2 no longer references bucket.bucketName (maybe the consumer stack now uses its own bucket, or it writes to an AWS DynamoDB table, or maybe you just remove the Lambda Function altogether).
- In the stack1 class, call this.exportValue(this.bucket.bucketName). This will make sure the CloudFormation Export continues to exist while the relationship between the two stacks is being broken.
export class Stack1 extends Stack {
readonly bucket: s3.Bucket
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props)
// Let's say there is a Bucket in the stack1, and the stack2 references its bucket.bucketName.
const bucket = new s3.Bucket(this, 'bucket', {
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
})
this.bucket = bucket
// Uncomment the following line
// This will make sure the CloudFormation Export continues to exist while the relationship between the two stacks is being broken.
this.exportValue(bucket.bucketName)
}
}
- Deploy (this will effectively only change the stack2, but it's safe to deploy both).
npx cdk deploy --all
DEPLOYMENT 2: remove the resource
- You are now free to remove the bucket resource from stack1.
- Don't forget to remove the exportValue() call as well.
- Deploy again (this time only the stack1 will be changed -- the bucket will be deleted).
That all, don't forget to remove clean all resources to avoid any unexpected AWS cost.
npx cdk destroy --all
Thanks for reading! I hope you found this helpful. If you have any questions, please contact me at Binh Bui or leave a comment. I will try to reply as soon as possible.