Last updated: Jan 27, 2024
Reading timeยท8 min
CDK bootstrap is a command we can access using the CDK CLI.
npx aws-cdk bootstrap
The cdk bootstrap
command provisions a CloudFormation stack called
CDKToolkit
. This CloudFormation stack is specific to the environment
(region and account) our CDK stack is
configured for.
Every CDK application belongs to a specific environment.
An environment consists of an account number and a region, where the CDK app is going to be deployed.
We set the environment for a CDK project when instantiating a CDK stack.
const app = new cdk.App(); const myStack = new MyCdkStack(app, 'my-cdk-stack', { stackName: `my-cdk-stack`, // ๐ set the environment env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
The initialization process of the environment consists of:
The CDKToolkit
stack provisions an S3 bucket that stores the assets(i.e.
Lambda code,
CloudFormation template, etc),
required for a CDK deployment.
In the S3 bucket we will have an assets
"directory".
The assets directory is going to contain our zipped file assets.
For a simple CDK project with a single lambda function, my file assets consist
of the index.js
handler code for the Lambda.
In order to bootstrap our default account and region we can run the
cdk bootstrap
command.
npx aws-cdk bootstrap
We only need to use the bootstrap
command once for every environment(region
and account).
If we use the command more than once, the
CDK CLI will check if our
CDKToolkit
stack has to be updated. If necessary, the stack will be updated.
If not, running the bootstrap
command does nothing.
We can also specify other environments to bootstrap.
npx aws-cdk bootstrap --profile my-profile npx aws-cdk bootstrap ACCOUNT_NUMBER/REGION npx aws-cdk bootstrap 123456789/us-east-1
The CDK bootstrap command provisions a CloudFormation stack called CDKToolkit
.
The stack consists of an S3 bucket that stores file assets (i.e. Lambda function code, CloudFormation templates), required for deployments.
We have to bootstrap each environment (account and region) separately.
To generate a CloudFormation template in AWS CDK we have to use the
cdk synth
command.
The cdk synth
command does a couple of things for us:
cdk.out
directoryIn order to demo the process, I'll create a small CDK application that consists of a single S3 bucket.
import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cdk from 'aws-cdk-lib'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); // ๐ create our Bucket resource const s3Bucket = new s3.Bucket(this, 'avatars-bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, }); } } const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack', { stackName: 'my-cdk-stack', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
In the code sample:
We defined our CDK stack and used the Bucket construct to create a bucket resource.
We instantiated our CDK stack in the scope of the CDK app.
To generate the CloudFormation template equivalent of our CDK stack, I have to
run the synth
command.
npx aws-cdk synth
The command outputs the complete CloudFormation equivalent of our CDK stack, in our case the S3 bucket.
If we take a look at the cdk.out
directory, we can see that our CloudFormation
template has been generated and is ready for deployment.
When we run the cdk deploy
command, the CDK CLI automatically runs the
cdk synth
command for us and generates the CloudFormation template.
At this point, we've generated the CloudFormation equivalent of our CDK stack
and we're ready to deploy using the cdk deploy
command.
The cdk synth
command from the
CDK CLI generates
and prints the CloudFormation equivalent of the CDK stack we've defined.
The code we write in our CDK applications gets compiled down to CloudFormation before it gets deployed.
CDK is just an abstraction level above CloudFormation that aims to improve developer experience. Our CDK code eventually ends up as CloudFormation before it gets deployed.
In order to synthesize a CloudFormation template, the CDK CLI has to first execute our CDK app.
I often run cdk synth
to execute my app and see if I get any errors.
The cdk synth
command knows how to execute our app because we've specified the
command as the value of the app
key in our cdk.json
file. This command is
different for the different programming languages CDK supports.
CDK projects written in TypeScript have to be compiled down to JavaScript, which
is done by executing the value of the app
key in the cdk.json
file:
{ "app": "npx ts-node --prefer-ts-exts infra/app.ts", "context": { // ... } }
In order to demo the cdk synth
command, I'll create a small CDK app,
consisting of a single s3 bucket.
import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cdk from 'aws-cdk-lib'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); new s3.Bucket(this, 'avatars-bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, }); } } const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack', { stackName: 'my-cdk-stack', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
I'll now run the synth
command:
npx aws-cdk synth
The output I get is the CloudFormation equivalent to my CDK stack (if we ignore the metadata section).
Resources: avatarsbucketE3043F49: Type: AWS::S3::Bucket UpdateReplacePolicy: Delete DeletionPolicy: Delete Metadata: aws:cdk:path: my-cdk-stack/avatars-bucket/Resource CDKMetadata: Type: AWS::CDK::Metadata Properties: Analytics: v2:deflate64:H... Metadata: aws:cdk:path: my-cdk-stack/CDKMetadata/Default
After I ran the cdk synth
command the CDK CLI created a cdk.out
folder in
the root directory of my project.
The cdk.out
folder contains the
generated cloudformation template(s)
and asset files if our application requires any assets.
Because a CDK app can consist of more than one CDK stack, we might end up having
multiple CloudFormation templates in the cdk.out
directory.
Let's test the behavior of cdk synth
if we have more than one stack
instantiated in our CDK App:
import * as cdk from 'aws-cdk-lib'; import {MyCdkStack} from '../lib/cdk-starter-stack'; const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack-dev', { stackName: 'my-cdk-stack-dev', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, }); new MyCdkStack(app, 'my-cdk-stack-prod', { stackName: 'my-cdk-stack-prod', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
I instantiated our CDK stack 2 times.
If I synthesize the stack now with:
npx aws-cdk synth
I get the following output:
The output states that both stacks have been synthesized in the
cdk.out
directory.
If we look at the contents of the cdk.out
directory, we can see that both of
our CloudFormation stacks have been generated.
When working with multiple stacks it's better to explicitly name the stacks.
npx aws-cdk synth \ my-cdk-stack-dev \ my-cdk-stack-prod
The printed output of the cdk synth
command is in YAML, however, the stored
output in our cdk.out
directory is in JSON.
If you want to print the output in JSON when running cdk synth
you can pass the
--json
flag.
npx aws-cdk synth --json my-cdk-stack-dev
The cdk synth
command executes our CDK app, generates the equivalent of our
CDK code as a CloudFormation template and stores it in the cdk.out
directory.
We can look at the command as a preparation step before a stack deployment.
Note that running the cdk synth
command before we run cdk deploy
is
optional, because CDK will run synth for us before each deployment
automatically.
The cdk diff
command outputs the difference between the already deployed
CloudFormation template and the CloudFormation template equivalent of our
current CDK code.
CDK is just a wrapper around CloudFormation that enables us to write our infrastructure as code using a programming language (TypeScript, Python, Java ...), rather than a configuration language (YAML, JSON).
Eventually, our CDK code gets compiled down to CloudFormation before it gets deployed.
To demo how the CDK diff command works, I'll create a small CDK app, consisting of a single S3 bucket.
import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cdk from 'aws-cdk-lib'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); new s3.Bucket(this, 'avatars-bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, }); } } const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack', { stackName: 'my-cdk-stack', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
We used the Bucket construct to create an S3 bucket.
Let's run the diff command before even deploying:
npx aws-cdk diff
The output looks as follows:
The output shows us that if we were to deploy our current CDK code, we'd create an S3 bucket.
When we ran the cdk diff
command a couple of things happened behind the
scenes:
The CDK CLI ran the
cdk synth
command.
The cdk synth
command first runs the code of our CDK app. It then generates
the CloudFormation equivalent of the CDK stack we've defined, and stores the
output in the cdk.out
directory.
If we look at the contents of the cdk.out
directory we can see the
CloudFormation equivalent of our CDK stack:
Then the cdk diff
command printed the changeset between the template from the
cdk.out
directory and the deployed
CloudFormation template.
Since we haven't deployed our stack yet, it just printed what we'd provision if we deployed the stack.
I'll now deploy the stack by running npx aws-cdk deploy
. Then I'll make a
small change to the application and run npx aws-cdk diff
again.
- new s3.Bucket(this, 'avatars-bucket', { + new s3.Bucket(this, 'another-bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY, });
I've just changed the id
parameter I'm passing to the Bucket construct.
Let's run the cdk diff
command again:
npx aws-cdk diff
And look at the output:
From the output, we see that our bucket will be destroyed and a new one will be created.
id
parameter, we've changed the CloudFormation logical ID of the resource.We can look at the current Logical ID of our Bucket in the CloudFormation console:
This is one of the more confusing aspects of CDK and can be quite the foot gun, so I've written another article on the topic - Identifiers in AWS CDK.
cdk diff
command before deploying is a very good practice, especially when updating stateful resources like databases.As a side note, we can also run the cdk diff
command to compare between a
CloudFormation template on our local file system and our current CDK code:
npx aws-cdk diff \ --template cdk.out/my-cdk-stack.template.json \ my-cdk-stack
We use the cdk diff
command to compare between the already deployed
CloudFormation template and the CloudFormation template that has been generated
by running the cdk synth
command and is equivalent to the current state of our
CDK app.
It's always a good practice to run the cdk diff
command before we deploy, to
avoid surprises with resources getting deleted due to a change in logical IDs.
You can learn more about the related topics by checking out the following tutorials: