If you don’t really understand terms like stack or nested stack, you probably don’t have a good grasp of CloudFormation yet, so please refer to this first:
With CloudFormation, you can create separate stacks like stack A, stack B, and stack C, and then combine them into a single architecture. To reference stack B from stack A, you use the Import and Outputs functions, but as the number of stacks grows, managing these references becomes a real hassle.

This is especially true when stacks reference each other. For example, stack A references values from stack B, and stack B also references values from stack A. In such cases, you need to use wait and other techniques to control the creation order of the stacks.
Also, deleting stacks with mutual references is a pain. You have to first remove the reference from stack A, then update stack B, delete stack A, and finally delete stack B. It’s a hassle.
At this point, you’ll want to combine everything into a single stack. That’s where nested stacks come in.
You create child stacks under a parent stack, and when you create the parent stack, all the child stacks are created together. When deleting, you can delete all the child stacks at once by deleting the parent stack.

First, I’ll explain the directory structure. Honestly, everyone does it differently, so just use this as a reference.
.
├── Makefile
└── nested-stack
├── architect-bucket
│ └── s3.yml
├── master.yml
├── package
│ └── packaged.yml
├── s3-1.yml
└── s3-2.yml
In CloudFormation, you often have to run AWS CLI commands multiple times. It’s really annoying to run such long commands every time.
aws cloudformation create-stack --stack-name myteststack --template-body file://sampletemplate.json --parameters ParameterKey=KeyPairName,ParameterValue=TestKey ParameterKey=SubnetIDs,ParameterValue=SubnetID1\\,SubnetID2
So, you can predefine these commands in a Makefile and then just run make create or something similar.
This folder contains the services to be deployed with CloudFormation. You put the stacks you want to create in this folder.
The process of creating nested stacks involves package → deploy. The package command uploads the local templates to S3, so this is for creating the S3 bucket.
You can use the mb command to create the S3 bucket, but it’s up to you.
For a proper explanation of the package command, refer to the official documentation. Here, I’ll just give a rough explanation.
The tedious steps required to create nested stacks are as follows:
Properties.TemplateURL in the parent templateTo simplify these cumbersome steps, we use the --s3-bucket option of the package command.
Since the command can get long, we write it in the Makefile. When you run make package, the child templates are uploaded to the s3 bucket, which is architect-bucket in this case.
# Makefile
# package
.PHONY: package
package:
@aws cloudformation package --template-file ./nested-stack/master.yml \
--s3-bucket architect-bucket \
--output-template-file ./nested-stack/package/packaged.yml
Then, the parent template master.yml is transformed into the packaged.yml template with the Properties.TemplateURL pointing to the URLs of the child templates.
# master.yml
AWSTemplateFormatVersion: 2010-09-09
Description: master
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-1.yml ← ローカルの相対パスがS3のURLに変換される
Parameters:
Name: !Ref Name
S3Bucket2:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-2.yml ← ローカルの相対パスがS3のURLに変換される
Parameters:
S3Name1: !GetAtt S3Bucket1.Outputs.OutputS3Name1
This is what the packaged.yml might look like after running the package command:
# packaged.yml
AWSTemplateFormatVersion: 2010-09-09
Description: master
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::CloudFormation::Stack
Properties:
https://s3.ap-northeast-1.amazonaws.com/nested-stack/なんちゃらなんちゃら.template
Parameters:
Name: !Ref Name
S3Bucket2:
Type: AWS::CloudFormation::Stack
Properties:
https://s3.ap-northeast-1.amazonaws.com/nested-stack/なんちゃらなんちゃら.template
Parameters:
S3Name1: !GetAtt S3Bucket1.Outputs.OutputS3Name1
Now you’re ready to deploy. Use the packaged.yml created earlier and run make deploy.
The deploy command conveniently handles the creation of the parent stack and the nested child stacks.
# Makefile
# deploy
.PHONY: deploy
deploy:
@aws cloudformation deploy \
--template-file nested-stack/package/packaged.yml \
--stack-name nested-stack \
To pass values from the parent stack to the nested child stacks, you can set the values in the Makefile and use the --parameter-overrides option with the deploy command.
# Makefile
Name := bokunonikki
# deploy
.PHONY: deploy
deploy:
@aws cloudformation deploy \
--template-file nested-stack/package/packaged.yml \
--stack-name nested-stack \
--parameter-overrides Name=${Name}
The value of Name is passed to the parent stack first. The master.yml looks like this:
By doing this, you can pass the value from the parent stack to the nested child stack s3-1.yml.
# master.yml
AWSTemplateFormatVersion: 2010-09-09
Description: master
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-1.yml
Parameters:
Name: !Ref Name
The s3-1.yml can be set up to receive the value from the parent stack like this. In this case, an S3 bucket named bokunonikki-1 will be created.
AWSTemplateFormatVersion: 2010-09-09
Description: nested-stack-s3-1
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketName: !Sub
- ${ Name }-1
- { Name: !Ref Name }
To pass values between nested child stacks, you can use the Outputs function.
For example, to pass a value from Stack A to Stack B, you would first make the value available in Stack A’s outputs:
AWSTemplateFormatVersion: 2010-09-09
Description: nested-stack-s3-1
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketName: !Sub
- ${ Name }-1
- { Name: !Ref Name }
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Outputs:
OutputS3Name1:
Value: !Ref S3Bucket1
Then, in Stack B, you would use !GetAtt to reference the output value from Stack A:
AWSTemplateFormatVersion: 2010-09-09
Description: master
Parameters:
Name:
Type: String
Resources:
S3Bucket1:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-1.yml
Parameters:
Name: !Ref Name
S3Bucket2:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./s3-2.yml
Parameters:
S3Name1: !GetAtt S3Bucket1.Outputs.OutputS3Name1 ← これ
Stack B itself doesn’t need any special configuration. You just set up the Parameters as usual.
AWSTemplateFormatVersion: 2010-09-09
Description: nested-stack-s3-2
Parameters:
S3Name1:
Type: String
Resources:
S3Bucket2:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
BucketName: !Sub
- ${ S3Name1 }-2
- { S3Name1: !Ref S3Name1 }
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
That’s all. Be careful not to just copy and paste these commands, as they haven’t been tested.
However, with this general knowledge, you should be able to figure things out by referring to the official documentation.
This book on Make is probably all you need. Even at a basic level, it can be quite helpful.
This book is great for getting a hands-on understanding of AWS services.