You can add properties to your CDK stacks and reference those in others. Behind the scenes each CloudFormation Stack creates outputs and parameters. (This may not always be ideal, as my particular use case made it more difficult to refactor and update the application.)
// Pipeline contains an ECR repository we'd like to reference elsewhere
public class PipelineStack : Stack
{
public IRepository EcrRepository { get; }
public PipelineStack(Construct parent, string id, IPipelineStackProps props)
: base(parent, id, props)
{
EcrRepository = new Repository(
this,
"EcrRepository",
new RepositoryProps
{
// props
});
// rest of stack...
}
}
// Given IApiStackProps similar to:
public interface IApiStackProps : IStackProps
{
IRepository Repository { get; }
}
// Now we'd like to load an ECR task found in that referenced repository
public class ApiStack : Stack
{
public ApiStack(Construct parent, string id, IApiStackProps props)
: base(parent, id, props)
{
var repo = Repository.FromRepositoryName(
this,
"EcrRepository",
props.Repository.RepositoryName);
var container = new ContainerDefinition(
this,
"ApiContainer",
new ContainerDefinitionProps
{
TaskDefinition = taskDef,
Image = ContainerImage.FromEcrRepository(repo, imageTag.ValueAsString),
});
// rest of stack...
}
}
This allows you to create two stacks quite simply sharing resources:
var app = new App(new AppProps());
var pipelineStack = new PipelineStack(app, "ExamplePipeline", new PipelineStackProps
{
// some props...
});
new ApiStack(app, apiStackName, new ApiStackProps
{
Repository = pipelineStack.EcrRepository,
});
This led me to create a series of stacks like the following diagram with the topmost stacks requiring resources from below:

From personal experience I'd recommend staying away from too many inter-stack dependencies for the aforementioned reasons. Where possible move "shared" or referenced resources into a base stack you can extend (.NET's Lazy<T> made this easy to only create resources when acessed). With this shared base approach the number of stacks will likely decrease and allow for easier long-term support and updating:

Unfortunately I do not have a good public example of this second approach, however, the code snippets above are from my ECS CDK example repo which shares a lot between stacks.