Skip to content

AWS CDK — Cloud Development Kit

From apprenticeship coursework and AWS docs.


Ultra-Short Summary

CDK lets you define AWS infrastructure using real programming languages (Python, TypeScript, Java) instead of JSON/YAML. You write code, CDK synthesises it into a CloudFormation template, and CloudFormation deploys it. The benefit: type safety, loops, conditionals, reusable components — things YAML can't do.


CDK vs CloudFormation vs Terraform

CloudFormation:
  -> AWS-native IaC, JSON or YAML templates
  -> Verbose, no loops or conditionals
  -> Everything is possible but tedious for complex infrastructure

Terraform:
  -> HCL (HashiCorp Config Language), multi-cloud
  -> More expressive than raw CF, state stored separately
  -> Large ecosystem, standard in many orgs

CDK:
  -> Write in Python, TypeScript, Java, C#, Go
  -> Compiles to CloudFormation
  -> Best of both: real code + native AWS integration
  -> You still get CloudFormation's rollback and state management

CDK is not a replacement for CloudFormation — it's a higher-level abstraction on top of it.


Core Concepts

App         -> top-level CDK program
  Stack     -> unit of deployment (one CloudFormation stack)
    Construct -> a reusable component (can be a single resource or many)

Hierarchy:
  App
  +-- Stack (dev)
  |     +-- Construct: VPC
  |     +-- Construct: ECS Cluster
  |           +-- Construct: Task Definition
  |           +-- Construct: Fargate Service
  +-- Stack (prod)
        +-- same constructs, different config

Constructs — Three Levels

Level Name Description Example
L1 Cfn (CloudFormation) Direct 1:1 mapping to CF resource CfnBucket
L2 Default Higher-level with sensible defaults s3.Bucket
L3 Patterns Complete solution patterns ecs_patterns.ApplicationLoadBalancedFargateService

Start with L2 (default), drop to L1 only if you need a CF property that L2 doesn't expose.


Setup and CLI

# Install CDK CLI
npm install -g aws-cdk

# Bootstrap your AWS account (one-time per region)
cdk bootstrap aws://ACCOUNT_ID/REGION

# Create a new project
mkdir my-app && cd my-app
cdk init app --language python

# Core workflow
cdk synth          # synthesise CloudFormation template (see what will deploy)
cdk diff           # show what will change vs what's deployed
cdk deploy         # deploy to AWS
cdk destroy        # tear down all resources in the stack

cdk bootstrap creates an S3 bucket and IAM roles CDK needs to deploy assets.


Python CDK Example

from aws_cdk import (
    Stack,
    aws_s3 as s3,
    aws_lambda as lambda_,
    aws_s3_notifications as s3n,
    Duration,
)
from constructs import Construct

class ProcessingStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs):
        super().__init__(scope, construct_id, **kwargs)

        # S3 bucket with versioning and encryption (L2 sensible defaults)
        bucket = s3.Bucket(
            self, "UploadBucket",
            versioned=True,
            encryption=s3.BucketEncryption.S3_MANAGED,
            removal_policy=RemovalPolicy.DESTROY,  # for dev/test only
        )

        # Lambda function
        processor = lambda_.Function(
            self, "Processor",
            runtime=lambda_.Runtime.PYTHON_3_12,
            handler="index.handler",
            code=lambda_.Code.from_asset("lambda"),
            timeout=Duration.seconds(30),
        )

        # Grant Lambda read access to bucket (CDK manages the IAM policy)
        bucket.grant_read(processor)

        # Trigger Lambda when objects are uploaded
        bucket.add_event_notification(
            s3.EventType.OBJECT_CREATED,
            s3n.LambdaDestination(processor),
        )

Key things to notice: - CDK generates IAM policies automatically (grant_read, grant_write) - Resources have logical IDs (UploadBucket, Processor) — CDK generates unique physical names - RemovalPolicy.DESTROY — CDK will delete the bucket on cdk destroy (dangerous in prod)


CDK Workflow

Write CDK code (Python/TypeScript)
        |
        v
cdk synth -> CloudFormation template (JSON)
        |
        v
cdk deploy -> CloudFormation executes the template
        |
        v
AWS resources created/updated

If anything fails:
  CloudFormation rolls back all changes automatically

Useful CDK Patterns

Environment-specific stacks

app = cdk.App()

ProcessingStack(app, "Dev",
    env=cdk.Environment(account="123456789", region="ap-southeast-2"),
    stage="dev",
)
ProcessingStack(app, "Prod",
    env=cdk.Environment(account="987654321", region="ap-southeast-2"),
    stage="prod",
)

CDK Context and Parameters

# Pass values at deploy time
cdk deploy --context instance_type=t3.large

# Read in code
instance_type = self.node.try_get_context("instance_type") or "t3.small"

Aspect for tagging all resources

cdk.Tags.of(app).add("Project", "my-app")
cdk.Tags.of(app).add("Environment", "prod")

CDK Constructs Library

The constructs library has patterns for common architectures:

from aws_cdk import aws_ecs_patterns as ecs_patterns

# One construct deploys: ECS Cluster + Fargate Service + ALB + Target Group + Security Groups
ecs_patterns.ApplicationLoadBalancedFargateService(
    self, "Service",
    cluster=cluster,
    cpu=512,
    memory_limit_mib=1024,
    task_image_options=ecs_patterns.ApplicationLoadBalancedTaskImageOptions(
        image=ecs.ContainerImage.from_registry("nginx"),
    ),
    public_load_balancer=True,
)

Mental Model

CloudFormation YAML = writing assembly language
CDK = writing Python that generates the assembly language

The compiler (CDK) knows AWS best practices:
  -> L2 constructs add encryption by default
  -> grant_read() creates the minimal necessary IAM policy
  -> Constructs wire resources together correctly

You think in architecture, CDK thinks in CloudFormation.

cdk diff = git diff for infrastructure -- see changes before deploying
cdk synth = dry run -- inspect what will be deployed without touching AWS

SAA / SAP Patterns

Scenario Answer
Reuse infrastructure across multiple apps CDK Construct (package and import)
Manage multiple environments from one codebase CDK Stacks with env parameters
Add tags to every resource across the app cdk.Tags.of(app).add(...)
Full-stack app deployment (ALB + ECS + RDS) CDK Patterns (L3 constructs)
Preview changes before deploying cdk diff
Roll back a bad deployment CloudFormation handles rollback automatically

Self-Quiz

  1. What does cdk synth produce and why should you run it before deploying?
  2. What's the difference between L1, L2, and L3 CDK constructs?
  3. Why do you need to run cdk bootstrap and what does it create?
  4. How does bucket.grant_read(processor) work — what does CDK generate?
  5. You want different resources in dev vs prod. How do you structure this in CDK?
  6. CDK deploy fails halfway through. What happens to the resources already created?
  7. What's the relationship between CDK and CloudFormation?
  8. When would you reach for L1 (Cfn) constructs instead of L2?