← Back to tech sharing
2026-08

Passing values between CloudFormation stacks: Export/Import, Nested Stacks, SSM Parameter Store

AWSCloudFormationIaC

Once infrastructure is split across multiple CloudFormation stacks, you always run into the same question: how does one stack reference another stack’s resource ID or ARN? This article covers the three common approaches — Export/Fn::ImportValue, Nested Stacks, and SSM Parameter Store — how each works, and when to reach for it.

1. Export / Fn::ImportValue

The producing stack defines an Export under Outputs; the consuming stack reads it with Fn::ImportValue.

# Producing stack
Outputs:
  VpcId:
    Value: !Ref Vpc
    Export:
      Name: shared-network-vpc-id

# Consuming stack
Resources:
  WebSg:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !ImportValue shared-network-vpc-id

Characteristics

  • Native CloudFormation functionality — no extra resources needed.
  • An exported value cannot be updated or the producing stack deleted while even one other stack still imports it (this also blocks updates that would change the value itself). This tight coupling is its biggest weakness.
  • Export names must be globally unique within the region, so naming collisions need care.

Good fit: distributing rarely-changing foundational values (a VPC ID, a base domain name) to many stacks.

2. Nested Stacks

The parent stack invokes a child template as an AWS::CloudFormation::Stack resource, and reads the child’s Outputs directly in the parent template via !GetAtt ChildStack.Outputs.XXX.

Resources:
  NetworkStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://.../network.yaml

  AppStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://.../app.yaml
      Parameters:
        VpcId: !GetAtt NetworkStack.Outputs.VpcId

Characteristics

  • Parent and children are managed as a single deployment unit — update-stack/delete-stack on the parent cascades to the children.
  • Avoids the “can’t delete because something else still references it” problem that Export/Import has, since everything is scoped to the parent’s lifecycle.
  • The trade-off: child templates must be uploaded to S3 first, adding a build/deploy step.
  • Parent-stack events, drift detection and rollbacks cascade into the children too, widening the blast radius of any deploy. Too many stacks nested too deep also gets hard to reason about.

Good fit: tightly-coupled resource groups that are always deployed and torn down together (e.g. the Lambda + DynamoDB + API Gateway set that makes up one microservice), packaged as a single template.

3. SSM Parameter Store

Values live outside any stack, in Systems Manager Parameter Store; both the producing and consuming stacks read/write through it.

# Producer: write the value as a parameter
Resources:
  VpcIdParam:
    Type: AWS::SSM::Parameter
    Properties:
      Name: /shared/network/vpc-id
      Type: String
      Value: !Ref Vpc

# Consumer: read it via a dynamic reference (resolved at deploy time)
Resources:
  WebSg:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: "{{resolve:ssm:/shared/network/vpc-id}}"

Characteristics

  • Stacks have no direct CloudFormation-level dependency on each other — none of Export/Import’s “can’t delete because it’s referenced” constraint.
  • {{resolve:ssm:...}} resolves the value at deploy time, so updating the parameter does not automatically propagate to stacks that reference it — they need an explicit redeploy. This constraint is similar to Export/Import.
  • Values can be shared across stacks, repos and even teams, and read from outside CloudFormation entirely (CLI, Lambda, other IaC tools) — much more general-purpose.
  • Parameters can carry their own IAM policies, making it easy to control who can read or write which value.

Good fit: loose coupling across teams, or when tools other than CloudFormation (CDK, Terraform, application code) need to read the same value.

Comparison

ApproachCouplingDeletion constraintScopeExtra cost
Export / Fn::ImportValueTightly coupled between stacksCan’t update/delete the producer while any importer still existsCloudFormation stacks in the same region onlyNone
Nested StackTightly coupled parent/child (one deploy unit)Deleting the parent deletes the children; well isolated from other stacksScoped under the parent templateChild templates must live in S3
SSM Parameter StoreLoosely coupledNo constraint — parameters exist independentlyReadable from outside CloudFormation, across teamsScales with parameter count (Standard tier has a free allowance)

When to reach for each

  • Low-churn foundational values owned by one team (a VPC ID, a shared KMS key) shared across a handful of stacks → plain Export/Import is usually enough, as long as you’re aware updates/deletes get harder over time.
  • Resource groups that are always deployed/destroyed together and worth packaging as a template → Nested Stacks, keeping an eye on nesting depth.
  • Cross-team/cross-repo collaboration, or values that need to be read by tools other than CloudFormationSSM Parameter Store is the most flexible, and increasingly the default for teams that prioritize loose coupling.

All three trade off the same axis: tightly coupled and simple but harder to change, versus loosely coupled and flexible but more moving parts to manage. Pick based on how the stacks are split, team structure, and how often the shared value actually changes.