- September 9, 2021
- By Brandon Dickson
- 6 min read
The AWS Cloud Development Kit and You
The AWS Cloud Development Kit allows you to model your cloud infrastructure in a number of programming languages.
BEFORE CDK
Introduction
In short
- AWS CDK models cloud infrastructure in programming languages like TypeScript, Python, Java, and .NET, generating CloudFormation templates from strongly typed classes.
- CDK automatically creates IAM roles and policies for resource interactions, handles stack dependencies, and deploys stacks in the correct order.
- Organizations can create reusable resource primitives with standard configurations, reducing documentation searches and ensuring consistent setup across teams.
I remember when I first started with AWS, many years ago. This was before Lambdas and much of their cloud offerings when we basically had S3 and EC2 instances. I manually configured all the things in the AWS console. I learned later, that this was bad, and started to describe my infrastructure with Cloud Formation Templates.
Cloud Formation Templates were a game-changer. I could now set up multiple environments exactly the same. This allowed me to find errors in my infrastructure configuration before we deployed to production, and became indispensable once I moved away from apps hosted on EC2 instances, and towards building apps with Lambdas and DynamoDB.
Managing the templates was a tedious process. My first templates were a couple of EC2 instances, perhaps a Cloud Front Distribution, and some Route53 bits. Now I was trying to handle dozens of Lambdas, and their associated IAM Roles, DynamoDB tables, SNS Topics, etc. A lot of the time, most of the configuration for any given resource was very similar, and after copying and pasting a few times, the cognitive dissonance was too much to bear, and I needed a programmatic solution.
I would write code that generated Cloud Formation Templates in JSON. Sometimes these took the form of a parser that would parse an existing template, add to it, and recompile it. Other times I found that building an object graph was a better approach. The problem was, with each new resource type I would need to poor over the documentation and design a class for it. This took the time I never seemed to have, and building a reusable library was a pipe dream.
Then one day, not too long ago, I discovered the AWS Cloud Development Kit. This was the library I always wanted but never had time to write.
WHAT IS CDK
What is The Cloud Development Kit?
The AWS Cloud Development Kit (CDK) allows you to model your cloud infrastructure in a number of programming languages, including Typescript, .Net, Java, and Python. Instead of creating templates with resources, you create classes that represent both templates and resources. You can then run a command-line utility that will compile your code, and use it to generate Cloud Formation templates. You can even deploy those templates with the same command-line utility.
Even if this was all you could do with it, that would be enough. Strongly typed Cloud Formation templates will save you from figuring out what typo you made in a YAML file, but wait, there's more...
STACK SHARING
Sharing Things Between Cloud Formation Stacks is Now Easy
I've certainly been there. I'm building this Cloud Formation template, and I keep adding things to it. It's a little heavy, but it's just one more resource... Boom. I hit the resource limit for a Cloud Formation stack. Now I've got to figure out how to break up the stack into two (or more), and I've got to get various ARNs and such from one template to another. When I deploy these stacks, I will also need to make sure I do it in the right order, so that outputs I need to reference in one stack exist on another stack.
CDK handles this for you in two ways. First, you use strings when you instantiate a resource class, like the name of an S3 bucket, but then pass the class instance around, and the CDK uses that to get the information it needs. Second, it builds a dependency graph of your stacks, so when you deploy one stack, it will traverse the graph, and deploy any stacks the deployed stack depends, on first.
export class StackA extends Stack {
// I'm exposing the S3 bucket as a property,
// so I can use it in other stacks.
myBucket: Bucket,
// "scope" is used by the CDK to manage
// the dependency graph.
constructor(scope: App) {
super(scope, "StackA");
// Create the S3 bucket.
// The first argument is the bucket's scope. In this case StackA.
this.myBucket = new Bucket(this, "MyBucket", {...});
}
}
...
export class StackB extends Stack {
constructor(scope: App, stackA: StackA) {
super(scope, "StackB");
// create a cloud front distribution
const dist = new CloudFrontWebDistribution(this, "MyDistribution", {
...,
originConfigs: [
{
s3OriginSource: {
// CDK uses the instance of the bucket class,
// I don't need to export the ARN from StackA.
// BONUS: Because myBucket's "scope" is StackA,
// using "cdk deploy StackB" will update/deploy StackA first
s3BucketSource: stackA.myBucket,
...
},
...
}
]
});
}
}
CODE REUSE
Using Language Paradigms You Are Familiar With
On my most recent project, I had the need to create 5 different micro-sites that only varied in a few ways, mainly domain and S3 bucket names. With plain Cloud Formation Templates, I would need to do a lot of copying/pasting. Moreover, if I wanted to make a unilateral change to how all sites work, perhaps a Cloud Front Distribution behavior, I would need to do it 5 times. This is where the programable nature of CDK really shines. I was able to create a subclass of Stack, that allowed me to only change what would be different for each site. This is basic OOP inheritance, but when using it to build Cloud Formation Templates, it becomes extremely powerful.
export type SiteStackProps = {
stackName: string,
subDomain: string,
s3BucketName: string
}
export abstract class SiteStack extends Stack {
bucket: Bucket,
distribution: CloudFrontWebDistribution,
constructor(scope: App, props: SiteStackProps) {
// The child class determines the stack name,
// since these are unique within an account.
super(scope, props.stackName);
// I create a bucket, but use the passed in bucket name.
this.bucket = new Bucket(this, "Bucket", {...})
// I create a cloud front distribution, but use the passed in domain name.
this.distribution = new CloudFrontWebDistribution(this, "Distribution", {...})
// More was created in the actual implementation, but this should give you the gist.
...
}
}
export class Site1Stack extends SiteStack {
constructor(scope: App) {
super(scope, {
stackName: "Site1Stack",
subDomain: "site-1",
s3BucketName: "site-1-bucket"
});
}
}
export class Site2Stack extends SiteStack {
constructor(scope: App) {
super(scope, {
stackName: "Site2Stack",
subDomain: "site-2",
s3BucketName: "site-2-bucket"
});
// For this stack, I may need to give
// bucket read access to some lambda.
// I can have access to all resources exposed
// as properties on the parent class.
this.bucket.grantRead(...)
}
}
ENTERPRISE SCALE
Immensely Powerful for Large Organizations
Most large organizations that have done any type of cloud development have specific requirements around how AWS resources are configured. It could be specific tags that denote what team owns the resource, or security rules around S3 bucket access, or encryption. Imagine if you could create a library of customized resource primitives with this configuration already done. This would prevent hours of searching through documentation as developers from different teams build out their own cloud infrastructure. You don't need to configure all the things for an S3 bucket, you simply have a CompanyS3Bucket class used by everyone, that adds tags or configures encryption the same way, for every S3 bucket across the organization.
THE TAKEAWAY
Conclusion
I hope this little post has served to highlight some of the features and benefits of using the CDK. I was able to convert a handful of Cloud Formation Templates to a full CDK implementation in a sprint, including building a Code Pipeline that would update itself and deploy all the things. I think this should be in the arsenal of anyone who builds AWS cloud infrastructure.
KEEP READING
Related Resources

Case Study
Automating 30,000 Daily Records for a Regional Bank
An AWS Lambda and Python pipeline now runs the transfer daily with no manual work, delivered in just under four months.
Read the regional bank case study
Case Study
Medical Record Extraction for a Healthcare Technology Company
Amazon Bedrock models and AWS Lambda now extract the data into a standard format, with less manual work and more accurate, timely reports.
Read the healthcare technology case study
Case Study
A GenAI Knowledge Base for a Building Materials Manufacturer
Employees ask questions in plain language and get answers almost instantly, from a knowledge base built on Amazon Bedrock and OpenSearch.
Read the building materials case study