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