03. AWS CDK
The AWS Cloud Development Kit (CDK) lets you define cloud infrastructure using familiar programming languages (TypeScript, JavaScript, Python, Java, .NET).
Instead of writing raw CloudFormation YAML/JSON, you model infrastructure as code the CDK synthesizes your code into a CloudFormation template which can then be deployed.
Why use CDK?
- Use a real programming language: loops, functions, modules, type checking, testing, code reuse.
- Higher-level constructs (L2/L3) simplify common patterns (VPCs, ECS services, ALBs, Lambda + DynamoDB).
- Smooth developer experience for serverless (Lambda) and containerized apps (ECS, EKS).
- Single toolchain for infra + app code (especially handy when using the same language for Lambdas).
Languages supported
- TypeScript / JavaScript
- Python
- Java
- .NET (C# / F# / VB)
⚙️ How It Works (High Level)
- Write your CDK app — Define Stacks and Constructs in Java to describe your AWS resources.
- Run
cdk synth— The CDK compiles your app and generates a CloudFormation template. - Run
cdk deploy— CDK uses CloudFormation to create or update resources in your AWS account. - Manage via CloudFormation — All resources are tracked and managed as CloudFormation stacks.
Typical CLI workflow
# initialize a new CDK project in Java
cdk init app --language java
# build the project (downloads dependencies, compiles sources)
mvn package
# generate the CloudFormation (CFN) template (no deploy)
cdk synth
# preview changes between deployed stack and local code
cdk diff
# deploy the stack to AWS
cdk deploy
# delete the deployed stack
cdk destroy
🚀 Create a Simple EC2 Instance using AWS CDK (Java)
EC2 + VPC + Security Group
Creates a Virtual Private Cloud (VPC), defines a Security Group that allows SSH access, and launches an EC2 instance inside that VPC using the latest Amazon Linux image.
🧱 Minimal Java Snippet
import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.ec2.*;
import software.constructs.Construct;
public class Ec2Stack extends Stack {
public Ec2Stack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Create a VPC
Vpc vpc = Vpc.Builder.create(this, "MyVpc")
.maxAzs(2)
.build();
// Create a Security Group
SecurityGroup sg = SecurityGroup.Builder.create(this, "MySecurityGroup")
.vpc(vpc)
.allowAllOutbound(true)
.description("Allow SSH access to EC2 instance")
.build();
// Allow SSH from anywhere
sg.addIngressRule(Peer.anyIpv4(), Port.tcp(22), "Allow SSH access");
// Launch EC2 Instance
Instance instance = Instance.Builder.create(this, "MyInstance")
.vpc(vpc)
.instanceType(InstanceType.of(InstanceClass.T3, InstanceSize.MICRO))
.machineImage(MachineImage.latestAmazonLinux2023())
.securityGroup(sg)
.keyName("my-keypair-name") // replace with your key pair
.build();
}
public static void main(final String[] args) {
App app = new App();
new Ec2Stack(app, "MyEc2Stack", StackProps.builder().build());
app.synth();
}
}
Best practices & tips
- Use constructs to encapsulate and reuse infra patterns.
- Keep Lambda code small and colocated with infra only when it makes sense.
- Use
cdk diffbeforecdk deployto see changes. - Use context and environment-specific stacks for multi-environment deployments.
- Write unit tests for constructs where practical (CDK asserts).