Skip to content

AWS CDK Reference: TypeScript IaC — L2/L3 Constructs, ECS Fargate, Aspects & Testing

AWS CDK (Cloud Development Kit) defines AWS infrastructure using TypeScript, Python, Java, or Go. You write real code with classes, loops, and abstractions — CDK synthesizes it to CloudFormation. The Construct model (L1/L2/L3) means common patterns like an ALB-backed ECS service become one or two lines instead of hundreds of CloudFormation YAML.

1. Install & Core Concepts

CDK setup, Constructs hierarchy, and project structure
Construct Level What it is Example
L1 (Cfn*) 1:1 CloudFormation resource — max control, verbose CfnBucket, CfnSecurityGroup
L2 Higher-level with defaults + helpers — use these s3.Bucket, ec2.SecurityGroup
L3 (Patterns) Multi-resource patterns (VPC + ALB + ECS in one class) ecs_patterns.ApplicationLoadBalancedFargateService
# Install CDK CLI:
npm install -g aws-cdk

# New TypeScript project:
mkdir my-infra && cd my-infra
cdk init app --language typescript
npm install

# Project structure:
# bin/my-infra.ts   — entry point (instantiates stacks)
# lib/my-infra-stack.ts  — your Stack class
# cdk.json          — CDK config
# cdk.context.json  — cached context (commit this)

# Bootstrap (one-time per AWS account + region):
cdk bootstrap aws://123456789/us-east-1

# Key commands:
cdk synth              # synthesize to CloudFormation (see what CDK generates)
cdk diff               # show changes (like terraform plan)
cdk deploy             # deploy (asks to confirm by default)
cdk deploy --require-approval never  # CI/CD
cdk destroy            # delete stack
cdk ls                 # list all stacks

2. Common Resources (TypeScript)

S3, DynamoDB, Lambda, SQS, and IAM in CDK
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as sqs from 'aws-cdk-lib/aws-sqs';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class MyStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // S3 bucket (L2 — sensible defaults):
    const bucket = new s3.Bucket(this, 'DataBucket', {
      versioned: true,
      encryption: s3.BucketEncryption.S3_MANAGED,
      removalPolicy: cdk.RemovalPolicy.RETAIN,    // don't delete on cdk destroy
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
    });

    // DynamoDB table:
    const table = new dynamodb.Table(this, 'OrdersTable', {
      tableName: 'orders',
      partitionKey: { name: 'orderId', type: dynamodb.AttributeType.STRING },
      sortKey: { name: 'createdAt', type: dynamodb.AttributeType.STRING },
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: cdk.RemovalPolicy.RETAIN,
    });

    // Lambda function:
    const fn = new lambda.Function(this, 'ProcessorFn', {
      runtime: lambda.Runtime.NODEJS_20_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda/processor'),
      environment: {
        TABLE_NAME: table.tableName,
        BUCKET_NAME: bucket.bucketName,
      },
      timeout: cdk.Duration.seconds(30),
      memorySize: 256,
    });

    // Grant permissions (CDK generates IAM policies automatically):
    table.grantReadWriteData(fn);        // adds dynamodb:PutItem, GetItem, etc.
    bucket.grantWrite(fn);               // adds s3:PutObject
  }
}

3. ECS Fargate Service (L3 Pattern)

VPC + ALB + ECS cluster + service in ~20 lines
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecs_patterns from 'aws-cdk-lib/aws-ecs-patterns';
import * as ecr from 'aws-cdk-lib/aws-ecr';

// VPC (2 AZs, public + private subnets):
const vpc = new ec2.Vpc(this, 'AppVpc', { maxAzs: 2 });

// ECS Cluster:
const cluster = new ecs.Cluster(this, 'AppCluster', { vpc });

// Container image from ECR:
const repo = ecr.Repository.fromRepositoryName(this, 'Repo', 'my-app');

// ALB + Fargate Service (L3 pattern — one construct does it all):
const service = new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'AppService', {
  cluster,
  cpu: 256,
  memoryLimitMiB: 512,
  desiredCount: 2,
  taskImageOptions: {
    image: ecs.ContainerImage.fromEcrRepository(repo, 'latest'),
    containerPort: 3000,
    environment: { NODE_ENV: 'production' },
    secrets: {
      DB_PASSWORD: ecs.Secret.fromSecretsManager(dbSecret, 'password')
    }
  },
  publicLoadBalancer: true,
});

// Auto-scaling:
const scaling = service.service.autoScaleTaskCount({ maxCapacity: 10 });
scaling.scaleOnCpuUtilization('CpuScaling', {
  targetUtilizationPercent: 70,
});

// Output the ALB URL:
new cdk.CfnOutput(this, 'LoadBalancerDNS', {
  value: service.loadBalancer.loadBalancerDnsName
});

4. Environments, Context & Cross-Stack References

Multi-environment stacks, cdk.json context, and sharing resources between stacks
// bin/my-infra.ts — instantiate per environment:
const app = new cdk.App();

// Get environment from context:
const env = app.node.tryGetContext('env') || 'dev';
const config = {
  dev:  { account: '111111111', region: 'us-east-1', instanceType: 't3.micro' },
  prod: { account: '222222222', region: 'us-east-1', instanceType: 't3.large' }
}[env];

new MyStack(app, `MyStack-${env}`, {
  env: { account: config.account, region: config.region },
  instanceType: config.instanceType,
});

// Deploy to specific env:
# cdk deploy --context env=prod

// Cross-stack references (export from one stack, import in another):
// stack1.ts:
this.bucket = new s3.Bucket(this, 'SharedBucket');
// Export (creates CloudFormation export):
new cdk.CfnOutput(this, 'BucketArn', { value: this.bucket.bucketArn, exportName: 'SharedBucketArn' });

// stack2.ts:
const sharedBucket = s3.Bucket.fromBucketArn(this, 'SharedBucket',
  cdk.Fn.importValue('SharedBucketArn')
);

// Or pass as props (cleaner — no CloudFormation export coupling):
// stack2.ts constructor receives { bucket: s3.IBucket }

// cdk.json context (cached VPC IDs, AMI lookups):
// {"context": {"@aws-cdk/core:enableStackNameDuplicates": true}}
// Context can be set via: cdk context --set key=value

5. Aspects, CDK Nag & Testing

Policy-as-code with Aspects, security scanning, and unit tests
// CDK Nag — security + compliance scanning (like cfn-guard):
// npm install cdk-nag

import { AwsSolutionsChecks } from 'cdk-nag';
import { Aspects } from 'aws-cdk-lib';

Aspects.of(app).add(new AwsSolutionsChecks({ verbose: true }));
// Runs on cdk synth — warns or fails on security issues:
// AwsSolutions-S1: S3 Bucket has server access logs disabled
// AwsSolutions-EC23: Security Group allows unrestricted inbound traffic
// Suppress a warning: NagSuppressions.addResourceSuppressions(bucket, [{id: 'AwsSolutions-S1', reason: 'Logging bucket'}])

// Custom Aspect (apply a tag to EVERY resource in a stack):
class TaggingAspect implements cdk.IAspect {
  visit(node: IConstruct) {
    if (node instanceof cdk.CfnResource) {
      cdk.Tags.of(node).add('CostCenter', 'platform');
      cdk.Tags.of(node).add('Environment', process.env.ENV || 'dev');
    }
  }
}
Aspects.of(stack).add(new TaggingAspect());

// Unit testing with Jest:
import { Template } from 'aws-cdk-lib/assertions';

test('S3 bucket has versioning enabled', () => {
  const app = new cdk.App();
  const stack = new MyStack(app, 'TestStack');
  const template = Template.fromStack(stack);
  template.hasResourceProperties('AWS::S3::Bucket', {
    VersioningConfiguration: { Status: 'Enabled' }
  });
});

test('Lambda has correct memory', () => {
  const template = Template.fromStack(stack);
  template.hasResourceProperties('AWS::Lambda::Function', {
    MemorySize: 256,
    Timeout: 30
  });
});

Track AWS CDK, CloudFormation, and AWS service releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.

Related: Pulumi Reference | Terraform Reference | GitHub Actions Reference

🔍 Free tool: npm Package Health Checker — check aws-cdk and related CDK packages for known CVEs and active maintenance before upgrading.

Founded

2023 in London, UK

Contact

hello@releaserun.com