CDK and CloudFormation are both ways to define your infrastructure as code, but they operate at vastly different levels of abstraction.
Let’s see CDK in action. Imagine you want to spin up a simple S3 bucket. With CDK, you can write this in TypeScript:
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
export class MyS3Stack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new s3.Bucket(this, 'MyBucket', {
versioned: true,
encryption: s3.BucketEncryption.S3_MANAGED,
});
}
}
When you cdk deploy, the CDK toolkit synthesizes this TypeScript code into a CloudFormation template. This template is what CloudFormation actually uses to create your resources.
Here’s a snippet of what that synthesized CloudFormation might look like:
Resources:
MyBucket0B32F5B9:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Enabled
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
This illustrates the core difference: CDK is a programming framework for defining infrastructure, while CloudFormation is the declarative engine that provisions it. CDK allows you to leverage the power of general-purpose programming languages (TypeScript, Python, Java, etc.) to define your infrastructure. This means you can use loops, conditional logic, functions, and even import external libraries to build complex, reusable infrastructure patterns. CloudFormation, on the other hand, is a declarative JSON or YAML language where you describe the desired state of your AWS resources.
The problem CDK solves is the inherent complexity and boilerplate often associated with writing raw CloudFormation. For example, if you needed 10 identical S3 buckets with slightly different names, in CloudFormation you’d be copying and pasting resource definitions. In CDK, you’d use a simple for loop. This abstraction makes it easier to manage, test, and reuse infrastructure code, especially in larger, more dynamic environments. CDK offers higher-level constructs that encapsulate common patterns, like a Vpc construct that provisions an entire Virtual Private Cloud with subnets, route tables, and NAT gateways, significantly reducing the amount of CloudFormation you’d otherwise need to write.
When you’re building a new application and need to quickly spin up standard AWS resources like EC2 instances, S3 buckets, or Lambda functions, CDK is often the faster and more flexible choice. Its programmatic nature allows for dynamic resource creation and complex configurations that would be cumbersome in raw CloudFormation. If you’re already using a particular programming language for your application, extending that into infrastructure management with CDK can feel very natural and improve developer velocity.
CloudFormation shines when you need precise, low-level control over every aspect of a resource’s configuration or when integrating with existing systems that already rely on CloudFormation templates. It’s also the bedrock upon which CDK and other IaC tools are built, so understanding its declarative nature is fundamental. For simple, static infrastructure deployments or when you’re dealing with complex AWS resource properties that might not yet be fully supported by higher-level CDK constructs, direct CloudFormation can be more straightforward.
The most surprising thing about CDK is how it handles dependencies and drift detection. While CloudFormation has its own drift detection, CDK leverages its synthesis process to create a manifest of your deployed resources. When you run cdk diff or cdk deploy, it compares your code to this manifest, providing a much more integrated and often more intuitive understanding of what changes will occur before they happen, and it can flag resources that have been modified outside of the CDK process.
The next concept you’ll likely explore is how to manage different environments (dev, staging, prod) using CDK, often involving environment-specific configurations and stack-level props.