I'm starting a new application using the AWS Cloud Development Kit (CDK) and I plan to organize my resources into different Stacks based on their expected lifetimes. I've come across suggestions to avoid cross-stack references because they can create complications if you need to modify or remove constructs later.
I'm curious about the pros and cons of passing instances of Construct objects to the constructors of dependent Stacks instead. It seems like this could be a practical approach during initial setup. For example, I'm setting up a VPC in its own stack and then passing that VPC instance to my database stack. Here's a snippet of how I'm structuring my code:
```python
class MyVpcStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
self.vpc = ec2.Vpc(# ... VPC params/config here ...)
class MyDbStack(Stack):
def __init__(self, scope: Construct, construct_id: str, vpc_instance: ec2.Vpc, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
db = rds.DatabaseInstance(self, 'MyDatabase', vpc=vpc_instance, # ...)
app = cdk.App()
vpc_stack = MyVpcStack(app, 'MyVpcStack')
db_stack = MyDbStack(app, 'MyDbStack', vpc_stack.vpc)
app.synth()
```
When I update shorter-lived stacks, won't the existing VPC instance just be referenced without any changes? Is using the instance like this a bad practice?
5 Answers
Using SSM parameters is a smart move. We’ve been applying this in our multi-account setups and it's super effective. You keep a singular source of truth, which simplifies things a lot. Makes it easier to manage resources across different environments too.
It's generally better to avoid cross-stack references because they can create dependencies that complicate resource management. Using SSM parameters to store essential values like ARNs or names is a smoother long-term solution, helping you avoid these messy dependencies in the first place.
One concern is about how CloudFormation manages stack dependencies. For instance, if you need to delete a resource that has outputs used by another stack, it won't let you. It's worth thinking about consolidating everything into one stack or using SSM parameters to keep things decoupled. This way, each stack can operate independently.
Just a heads up: passing stack instances might seem straightforward, but it can effectively auto-generate cross-stack references under the hood. So, you're not avoiding the complexity, just masking it.
Passing instances between stacks can work initially, but it might lead to issues later on when you try to update or remove constructs. You could face problems like not being able to delete a resource that's still referenced by another stack. Consider the scalability of your application too!

Aren't there limits on how many resources can be in a single stack? I thought it was around 500 resources, which could be a hassle for larger projects.