Claude Code for AWS CDK: Infrastructure as TypeScript — Claude Skills 360 Blog
Blog / DevOps / Claude Code for AWS CDK: Infrastructure as TypeScript
DevOps

Claude Code for AWS CDK: Infrastructure as TypeScript

Published: November 6, 2026
Read time: 8 min read
By: Claude Skills 360

AWS CDK lets you define cloud infrastructure in TypeScript — real code, not YAML. Constructs compose into Stacks, Stacks assemble into Apps, and CDK synthesizes CloudFormation. The result: your VPC, RDS cluster, ECS service, and Route 53 records share types, can be parameterized with variables, and can be unit tested. Claude Code writes CDK Constructs, contextual Stack configurations, CDK Pipelines for self-mutating CI/CD, and the L3 patterns that deploy production-ready AWS architectures in minutes.

CLAUDE.md for CDK Projects

## CDK Stack
- AWS CDK v2 TypeScript
- Constructs: L1 (raw CFN), L2 (sensible defaults), L3 (custom patterns)
- One Stack per logical boundary: VpcStack, DatabaseStack, AppStack
- Environment config: context in cdk.json, not hardcoded ARNs
- Secrets: SecretsManager (never string literals in stack)
- Removal policy: RETAIN on production databases; DESTROY only in dev
- Asset bundling: bundling option in NodejsFunction/DockerImageFunction
- CDK Pipelines: self-mutating pipeline via CodePipeline

Core Stack Structure

// lib/app-stack.ts — main application stack
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { Construct } from 'constructs';

interface AppStackProps extends cdk.StackProps {
  environment: 'dev' | 'staging' | 'production';
  vpcId?: string;  // Use existing VPC if provided
}

export class AppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: AppStackProps) {
    super(scope, id, props);
    
    const isProduction = props.environment === 'production';
    
    // VPC: use existing or create new
    const vpc = props.vpcId
      ? ec2.Vpc.fromLookup(this, 'Vpc', { vpcId: props.vpcId })
      : new ec2.Vpc(this, 'Vpc', {
          maxAzs: isProduction ? 3 : 2,
          natGateways: isProduction ? 3 : 1,
        });
    
    // RDS: environment-aware sizing
    const db = new rds.DatabaseInstance(this, 'Database', {
      engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_16 }),
      instanceType: isProduction
        ? ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.MEDIUM)
        : ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.MICRO),
      vpc,
      vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
      multiAz: isProduction,
      allocatedStorage: isProduction ? 100 : 20,
      storageEncrypted: true,
      deletionProtection: isProduction,
      removalPolicy: isProduction ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
      backupRetention: isProduction ? cdk.Duration.days(7) : cdk.Duration.days(1),
    });
    
    // ECS Fargate service
    const cluster = new ecs.Cluster(this, 'Cluster', { vpc, containerInsights: true });
    
    const taskDef = new ecs.FargateTaskDefinition(this, 'TaskDef', {
      memoryLimitMiB: isProduction ? 2048 : 512,
      cpu: isProduction ? 1024 : 256,
    });
    
    taskDef.addContainer('App', {
      image: ecs.ContainerImage.fromAsset('./app', {
        buildArgs: { NODE_ENV: props.environment },
      }),
      portMappings: [{ containerPort: 3000 }],
      environment: { NODE_ENV: props.environment },
      secrets: {
        DATABASE_URL: ecs.Secret.fromSecretsManager(db.secret!, 'password'),
      },
      logging: ecs.LogDrivers.awsLogs({ streamPrefix: 'app' }),
    });
    
    const service = new ecs.FargateService(this, 'Service', {
      cluster,
      taskDefinition: taskDef,
      desiredCount: isProduction ? 2 : 1,
      circuitBreaker: { rollback: true },
    });
    
    // Grant DB connection
    db.connections.allowDefaultPortFrom(service);
    
    // ALB
    const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
      vpc,
      internetFacing: true,
    });
    
    const listener = alb.addListener('HttpsListener', {
      port: 443,
      certificates: [/* ACM cert */],
    });
    
    listener.addTargets('AppTargets', {
      port: 3000,
      targets: [service],
      healthCheck: { path: '/health', interval: cdk.Duration.seconds(30) },
    });
    
    // Outputs
    new cdk.CfnOutput(this, 'LoadBalancerDns', { value: alb.loadBalancerDnsName });
  }
}

Custom L3 Construct

// lib/constructs/postgres-cluster.ts — reusable L3 construct
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
import { Construct } from 'constructs';

export interface PostgresClusterProps {
  vpc: ec2.IVpc;
  instanceSize: 'micro' | 'small' | 'medium' | 'large';
  multiAz?: boolean;
  databaseName: string;
}

export class PostgresCluster extends Construct {
  readonly instance: rds.DatabaseInstance;
  readonly secret: secretsmanager.ISecret;
  readonly connections: ec2.Connections;
  
  constructor(scope: Construct, id: string, props: PostgresClusterProps) {
    super(scope, id);
    
    const instanceClassMap = {
      micro: ec2.InstanceSize.MICRO,
      small: ec2.InstanceSize.SMALL,
      medium: ec2.InstanceSize.MEDIUM,
      large: ec2.InstanceSize.LARGE,
    };
    
    this.instance = new rds.DatabaseInstance(this, 'Instance', {
      engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_16 }),
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T4G,
        instanceClassMap[props.instanceSize],
      ),
      vpc: props.vpc,
      vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
      multiAz: props.multiAz ?? false,
      databaseName: props.databaseName,
      storageEncrypted: true,
    });
    
    this.secret = this.instance.secret!;
    this.connections = this.instance.connections;
  }
}

CDK Pipelines (Self-Mutating CI/CD)

// lib/pipeline-stack.ts — self-mutating pipeline
import * as cdk from 'aws-cdk-lib';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import { Construct } from 'constructs';
import { AppStack } from './app-stack';

export class PipelineStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: cdk.StackProps) {
    super(scope, id, props);
    
    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'AppPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('org/repo', 'main'),
        commands: [
          'npm ci',
          'npm run build',
          'npx cdk synth',
        ],
      }),
    });
    
    // Staging stage with manual approval gate
    const staging = pipeline.addStage(new AppStage(this, 'Staging', {
      environment: 'staging',
    }));
    staging.addPost(new ShellStep('IntegrationTests', {
      commands: ['npm run test:integration'],
    }));
    
    // Production (manual approval required)
    pipeline.addStage(new AppStage(this, 'Production', {
      environment: 'production',
    }), {
      pre: [new cdk.pipelines.ManualApprovalStep('PromoteToProduction')],
    });
  }
}

class AppStage extends cdk.Stage {
  constructor(scope: Construct, id: string, props: { environment: 'staging' | 'production' } & cdk.StageProps) {
    super(scope, id, props);
    new AppStack(this, 'AppStack', { environment: props.environment });
  }
}

For the Terraform alternative to CDK for multi-cloud infrastructure, the Terraform advanced guide covers modules, remote state, and drift detection. For the Pulumi alternative that also uses TypeScript, the Pulumi guide covers ComponentResource patterns and the Automation API. The Claude Skills 360 bundle includes AWS CDK skill sets covering L2/L3 Constructs, CDK Pipelines, and environment-aware Stack patterns. Start with the free tier to try CDK Stack generation.

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free