AWS CDK - Part II

Imagine you're building a house. Normally, you'd write down a detailed blueprint on a piece of paper (like a CloudFormation template in YAML or JSON) and hand it to the construction team. That works, but it's tedious. Now imagine you could use a programming language like TypeScript to generate that blueprint, add logic, loops, and conditions β and then push one button to build the entire house. That's AWS CDK in a nutshell.
AWS CDK (Cloud Development Kit) is an open-source framework that lets you define your cloud infrastructure using familiar programming languages like TypeScript, Python, Java, C#, and Go, instead of writing static YAML or JSON templates. Under the hood, it translates your code into CloudFormation templates and deploys them to AWS.
How Does It Work? The Big Picture
Let me explain the lifecycle of a CDK app:
Step 1: Write Code
You write TypeScript code that describes what AWS resources you want (e.g., an S3 bucket, a Lambda function, an API Gateway).
Step 2: Synthesize
CDK "synthesizes" your code β meaning it translates your TypeScript into a CloudFormation template. This template is a declarative YAML or JSON file that CloudFormation understands.
Step 3: Deploy
CDK uploads that template to CloudFormation, which then provisions all the AWS resources described in it. This is a one-time setup for your account in a region.
Step 4: Manage
You can update your code, run cdk diff to see what changed, and run cdk deploy again to apply updates. CDK handles all the heavy lifting of updating CloudFormation stacks.
Why Should You Use AWS CDK?
Here are the practical benefits:
| Benefit | What It Means For You |
|---|---|
| Write infrastructure in real code | Use if statements, loops, variables, and functions to create dynamic infrastructure β something impossible with static YAML |
| Autocomplete & type checking | Your IDE helps you write correct infrastructure code with less trial and error |
| Sensible defaults | CDK provides L2 constructs with smart defaults, so you write less code to get more done |
| Reusable components | Create your own constructs and share them across projects β just like npm packages |
| Same benefits as CloudFormation | You still get repeatable deployments, easy rollbacks, and drift detection |
Core Concepts You Need to Know
The Three-Level Construct System
CDK organizes AWS resources into three levels of constructs β think of them as "Lego blocks" at different levels of detail:
| Level | What It Is | Example |
|---|---|---|
| L3 Constructs | High-level patterns (entire applications) | An entire serverless API with Lambda, API Gateway, and DynamoDB |
| L2 Constructs (RECOMMENDED) | AWS resources with sensible defaults & helper methods | new s3.Bucket(this, 'MyBucket') |
| L1 Constructs (Cfn*) | Direct 1:1 mapping to CloudFormation resources | new s3.CfnBucket(this, 'MyBucket') |
Rule of thumb: Use L2 constructs whenever possible β they save you time and follow AWS best practices. L1 constructs are only useful when an AWS feature isn't yet available as an L2.
The Hierarchy: App β Stack β Construct
App (your entire CDK project)
βββ Stack (represents a CloudFormation stack β deployed as a unit)
βββ Constructs (individual AWS resources like S3 buckets, Lambda functions)
App: The root container for your entire CDK project. One app can contain multiple stacks.
Stack: A collection of resources that get deployed together as a single CloudFormation stack. In production, you might have separate stacks for networking, database, and application.
Construct: The basic building block representing an AWS resource (or collection of resources).
Getting Started: Your First CDK Project (Step by Step)
Prerequisites
Before you start, make sure you have:
Node.js (version 14 or later) β Download here
AWS CLI installed and configured with your AWS credentials β Install guide
TypeScript knowledge (basic to intermediate is fine)
Step 1: Install the CDK Toolkit
Open your terminal and run:
npm install -g aws-cdk
This installs the CDK CLI globally on your machine.
Verify the installation:
cdk --version
Step 2: Create Your First CDK Project
Create a new directory and initialize a TypeScript CDK app:
mkdir my-first-cdk-project
cd my-first-cdk-project
cdk init app --language typescript
This creates a complete project structure for you.
Your project structure will look like this:
my-first-cdk-project/
βββ bin/
β βββ my-first-cdk-project.ts # Entry point (creates the App)
βββ lib/
β βββ my-first-cdk-project-stack.ts # Your stack definition
βββ test/ # Unit tests
βββ package.json # Dependencies
βββ tsconfig.json # TypeScript configuration
βββ cdk.json # CDK-specific configuration
Step 3: Bootstrap Your AWS Account (IMPORTANT)
Before you can deploy anything, you must bootstrap your AWS account. Bootstrapping prepares your AWS account by creating an S3 bucket and IAM roles that CDK needs to manage deployments.
Run this command once per account/region:
cdk bootstrap aws://YOUR_ACCOUNT_NUMBER/YOUR_REGION
For example:
cdk bootstrap aws://123456789012/us-east-1
If you have AWS CLI configured correctly, you can simply run:
cdk bootstrap
Step 4: Write Your First Infrastructure Code
Open lib/my-first-cdk-project-stack.ts and replace the content with a simple static website example:
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
import { Construct } from 'constructs';
export class MyFirstCdkProjectStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Create an S3 bucket for website hosting
const websiteBucket = new s3.Bucket(this, 'MyWebsiteBucket', {
websiteIndexDocument: 'index.html', // Default page
publicReadAccess: true, // Make it publicly readable
removalPolicy: cdk.RemovalPolicy.DESTROY, // Delete bucket when stack is destroyed
autoDeleteObjects: true, // Delete all files when bucket is removed
});
// Deploy website files from your local folder to S3
new s3deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [s3deploy.Source.asset('./website-content')], // Folder with HTML files
destinationBucket: websiteBucket,
});
// Output the website URL so you can access it
new cdk.CfnOutput(this, 'WebsiteURL', {
value: websiteBucket.bucketWebsiteUrl,
});
}
}
What's happening here:
new s3.Bucket(...)creates an S3 bucket β this is an L2 construct that provides smart defaults for hosting a static website.new s3deploy.BucketDeployment(...)uploads your local website files to that bucket.new cdk.CfnOutput(...)prints the website URL after deployment.
Step 5: Create Your Website Content
Create a folder called website-content in your project root and add a simple index.html file:
mkdir website-content
echo '<h1>Hello from AWS CDK!</h1><p>My first infrastructure as code deployment!</p>' > website-content/index.html
Step 6: Install Required Dependencies
npm install @aws-cdk/aws-s3 @aws-cdk/aws-s3-deployment
Step 7: Check What You're About to Deploy (Safety First!)
Always run cdk diff before deploying to see what will change in your AWS account:
cdk diff
This shows you the exact CloudFormation changes that will happen β including which resources will be created, modified, or deleted.
Step 8: Deploy to AWS
cdk deploy
CDK will:
Synthesize your TypeScript into a CloudFormation template
Upload assets (like your website HTML) to an S3 bucket CDK manages
Deploy the stack using CloudFormation
After deployment completes, you'll see the WebsiteURL output β click it to see your live website!
Step 9: Clean Up (Important!)
When you're done experimenting, always clean up to avoid unexpected charges:
cdk destroy
This removes all resources created by your stack. The S3 bucket will be automatically emptied and deleted thanks to the autoDeleteObjects property we set.
Essential CDK Commands You'll Use Every Day
| Command | What It Does | When To Use It |
|---|---|---|
cdk init |
Creates a new CDK project | Starting a new project |
cdk synth |
Generates the CloudFormation template | Preview what CDK will produce; useful for debugging |
cdk diff |
Shows differences between your code and what's deployed | Before every deployment to avoid surprises |
cdk deploy |
Deploys (or updates) your infrastructure | To actually create/update AWS resources |
cdk destroy |
Deletes all resources in the stack | To clean up after testing |
cdk ls |
Lists all stacks in your app | To see what stacks are available |
cdk bootstrap |
Prepares your AWS account for CDK | First-time setup per account/region |
Putting It All Together: A Complete Workflow
Here's the typical workflow for a day of CDK development:
# 1. Open your project
cd my-project
# 2. Make changes to your infrastructure code (lib/*.ts)
# ... edit the code ...
# 3. Check what changed (ALWAYS do this)
cdk diff
# 4. If everything looks good, deploy
cdk deploy
# 5. Test your application
# ... browse to your website, call your API, etc. ...
# 6. When done for the day, clean up (for test environments)
cdk destroy
Best Practices for Real Projects
Based on AWS official guidance and community experience, here are key best practices:
1. Use Stages for Different Environments
Create a flexible dev and prod setup using the same codebase:
// bin/app.ts
import * as cdk from 'aws-cdk-lib';
import { MyAppStack } from '../lib/my-app-stack';
const app = new cdk.App();
// Development environment β can be destroyed easily
new MyAppStack(app, 'MyAppStack-Dev', {
env: { account: '111111111111', region: 'us-east-1' },
environmentName: 'dev',
ecsDesiredCount: 1,
});
// Production environment β careful with data!
new MyAppStack(app, 'MyAppStack-Prod', {
env: { account: '111111111111', region: 'us-east-1' },
environmentName: 'prod',
ecsDesiredCount: 3,
});
2. Use L2 Constructs Whenever Possible
L2 constructs provide smart defaults and helper methods like grantRead() that automatically create appropriate IAM permissions.
3. Always Use cdk diff Before cdk deploy
This simple habit saved countless developers from accidentally deleting production databases.
4. Store Sensitive Values in AWS Secrets Manager or SSM
Never hardcode passwords, API keys, or tokens in your CDK code.
Common Gotchas (What to Watch Out For)
Data loss risk: If you change a resource that can't be updated in place (like DynamoDB table name), CDK will replace it β potentially deleting data. Always review
cdk diffcarefully!Bootstrap required: You must bootstrap each AWS account and region you deploy to. This is a one-time setup.
Stack limits: CloudFormation has limits on stack size (500 resources maximum). Plan your architecture accordingly.
Costs: CDK itself is free, but the AWS resources it creates cost money. Always run
cdk destroyafter testing.
Summary
AWS CDK transforms how you build cloud infrastructure by letting you use TypeScript instead of YAML. You get the power of real programming (variables, loops, functions, conditionals) combined with the reliability of CloudFormation. The learning curve is gentle β you can deploy your first S3 static website in under 30 minutes.
Key takeaways:
CDK = Infrastructure as Code with real programming languages
App β Stack β Construct is the hierarchy
Use L2 constructs for almost everything
Always
cdk diffbeforecdk deployBootstrap once per account/region
cdk destroywhen done testing
Now go build something amazing with AWS CDK and TypeScript! π
Have questions or want to share what you built? Feel free to drop a comment below!





