AI Tools Compared

AWS CDK (Cloud Development Kit) replaces CloudFormation YAML templates with object-oriented code, reducing boilerplate and enabling composition of reusable infrastructure components. However, CDK’s learning curve is steep: L3 construct nuances, synth output validation, stack composition patterns, and cross-account exports require deep AWS expertise.

AI assistants vary dramatically in CDK capability. Some understand construct libraries and proper property initialization; others generate code that synthesizes but fails on deployment. This guide evaluates tools on real scenarios: VPC + subnet setup, RDS instance provisioning, Lambda function deployment with IAM, and multi-stack applications.

Claude Opus 4.6 (Best CDK Depth)

Pricing: $3/MTok input, $15/MTok output via API; Claude.ai subscriptions $20/month.

Strengths:

Example Output (VPC + RDS):

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';

export class DatabaseStack extends cdk.Stack {
  public readonly dbSecurityGroup: ec2.SecurityGroup;
  public readonly dbInstance: rds.DatabaseInstance;

  constructor(scope: cdk.App, id: string, vpc: ec2.Vpc, props?: cdk.StackProps) {
    super(scope, id, props);

    this.dbSecurityGroup = new ec2.SecurityGroup(this, 'DBSecurityGroup', {
      vpc,
      description: 'Security group for RDS instance',
      allowAllOutbound: true,
    });

    this.dbSecurityGroup.addIngressRule(
      ec2.Peer.securityGroupId(vpc.vpcId),
      ec2.Port.tcp(5432),
      'Allow PostgreSQL from VPC'
    );

    this.dbInstance = new rds.DatabaseInstance(this, 'PostgresDB', {
      engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_15_2 }),
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.SMALL),
      vpc,
      securityGroups: [this.dbSecurityGroup],
      databaseName: 'myappdb',
      credentials: rds.Credentials.fromGeneratedSecret('postgres', {
        secretName: 'rds-postgres-password',
      }),
      multiAz: true,
      storageEncrypted: true,
      deleteProtection: true,
      removalPolicy: cdk.RemovalPolicy.SNAPSHOT,
    });

    new cdk.CfnOutput(this, 'DBEndpoint', {
      value: this.dbInstance.dbInstanceEndpointAddress,
      exportName: 'DatabaseEndpoint',
    });
  }
}

Weaknesses:

Best For: Production infrastructure, enterprise stacks, multi-account deployments, security-critical configurations.

Cost/Article Ratio: ~$0.40–$0.60 per complex stack article (VPC + RDS + Lambda + monitoring). Higher upfront cost, lower revision cycles.


ChatGPT 4o (Reliable Basics; Gaps on Advanced Patterns)

Pricing: $20/month Pro, or API $0.003/$0.006 per 1K tokens.

Strengths:

Example Output (S3 + CloudFront):

import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';

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

    const bucket = new s3.Bucket(this, 'WebsiteBucket', {
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      versioned: false,
      encryption: s3.BucketEncryption.S3_MANAGED,
    });

    const distribution = new cloudfront.Distribution(this, 'Distribution', {
      defaultBehavior: {
        origin: new cloudfront.origins.S3Origin(bucket),
        viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
      },
    });

    new cdk.CfnOutput(this, 'DistributionURL', {
      value: distribution.distributionDomainName,
    });
  }
}

Weaknesses:

Best For: Tutorial content, getting-started guides, educational articles targeting beginners.

Cost/Article Ratio: ~$0.15–$0.25 per article. Fast output, but requires more editorial review on security and advanced topics.


GitHub Copilot (Context-Dependent; IDE-Bound)

Pricing: $10/month, $21/user/month enterprise.

Strengths:

Example Trigger:

// Copilot autocompletes from comment
// Create a Lambda function with auto IAM role
const lambdaFunction = new lambda.Function(this, 'MyFunction', {
  runtime: lambda.Runtime.NODEJS_18_X,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('lambda'),
  // ... Copilot fills in common properties
});

Weaknesses:

Best For: Snippets and boilerplate within existing projects; not recommended for generating new stacks from scratch.

Cost/Article Ratio: Not recommended for CDK article generation. Better suited to supporting developers writing their own code.


Cursor (Claude Backbone; Strong but Limited Scope)

Pricing: $20/month Pro, free tier available.

Strengths:

Weaknesses:

Best For: Individual developers writing CDK; not cost-effective for content generation at scale.

Cost/Article Ratio: ~$0.30–$0.50 per article. Slower than Claude API for batch generation.


Codeium (Fast Completions; Weak CDK Knowledge)

Pricing: Free, $12/month Pro.

Strengths:

Weaknesses:

Best For: Syntax completion only; not for generating functional CDK code.

Cost/Article Ratio: Not recommended. Saves minimal time; increases error correction overhead.


TabbyML (Open Source; Minimal CDK Support)

Pricing: Free (self-hosted), enterprise licensing.

Strengths:

Weaknesses:

Best For: Documentation scaffolding only; unsuitable for production CDK generation.


Comparison Table

Tool TypeScript Constructs IAM Policies Cross-Stack Best Practices Cost/Article Recommended
Claude Opus 4.6 Excellent Excellent Excellent Excellent Excellent $0.40–0.60 Yes
ChatGPT 4o Good Good Fair Fair Fair $0.15–0.25 Conditional
Copilot Good Fair Poor Poor Fair Subscription No
Cursor Excellent Excellent Excellent Excellent Excellent $0.30–0.50 Conditional
Codeium Fair Poor Poor Poor Poor Free–$12/mo No
TabbyML Fair Poor Poor Poor Poor Free No

Practical Workflow: Multi-Stack VPC + RDS + Lambda Application

Scenario: Build a production-ready application with networking, database, and compute layers.

Prompt 1 (VPC Stack): “Write a CDK TypeScript stack that creates a VPC with public and private subnets across 3 AZs. Use VPC CIDR 10.0.0.0/16. Public subnets use /24, private subnets use /24. Include NAT Gateway for private subnet egress.”

Claude Output (30 seconds):

import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

export class NetworkStack extends cdk.Stack {
  public readonly vpc: ec2.Vpc;

  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    this.vpc = new ec2.Vpc(this, 'MainVPC', {
      cidr: '10.0.0.0/16',
      maxAzs: 3,
      subnetConfiguration: [
        {
          subnetType: ec2.SubnetType.PUBLIC,
          name: 'PublicSubnets',
          cidrMask: 24,
        },
        {
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
          name: 'PrivateSubnets',
          cidrMask: 24,
        },
      ],
      natGateways: 1,
    });

    new cdk.CfnOutput(this, 'VpcId', {
      value: this.vpc.vpcId,
      exportName: 'NetworkStack-VpcId',
    });
  }
}

Prompt 2 (Database Stack): “Create a CDK stack that provisions a PostgreSQL RDS instance in the VPC from NetworkStack. Use t3.small, 20GB storage, encrypted, deletion protection enabled. Accept VPC as constructor parameter.”

Claude Output (20 seconds):

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';

export class DatabaseStack extends cdk.Stack {
  public readonly dbInstance: rds.DatabaseInstance;

  constructor(scope: cdk.App, id: string, vpc: ec2.Vpc, props?: cdk.StackProps) {
    super(scope, id, props);

    this.dbInstance = new rds.DatabaseInstance(this, 'PostgresDB', {
      engine: rds.DatabaseInstanceEngine.postgres({
        version: rds.PostgresEngineVersion.VER_15_2,
      }),
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.SMALL),
      vpc,
      vpcSubnets: {
        subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
      },
      credentials: rds.Credentials.fromGeneratedSecret('postgres'),
      databaseName: 'appdb',
      storageEncrypted: true,
      deleteProtection: true,
      removalPolicy: cdk.RemovalPolicy.SNAPSHOT,
      multiAz: true,
    });

    new cdk.CfnOutput(this, 'DBEndpoint', {
      value: this.dbInstance.dbInstanceEndpointAddress,
      exportName: 'DatabaseStack-DBEndpoint',
    });
  }
}

Prompt 3 (Lambda Stack): “Create a Lambda function that connects to the RDS database. Auto-generate IAM role with least-privilege permissions. Handler is index.handler in src/lambda directory. Add secrets manager permissions to retrieve RDS password.”

Claude Output (25 seconds):

import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

export class ComputeStack extends cdk.Stack {
  constructor(
    scope: cdk.App,
    id: string,
    vpc: ec2.Vpc,
    dbInstance: rds.DatabaseInstance,
    props?: cdk.StackProps
  ) {
    super(scope, id, props);

    const lambdaFunction = new lambda.Function(this, 'AppFunction', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('src/lambda'),
      vpc,
      vpcSubnets: {
        subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
      },
      environment: {
        DB_HOST: dbInstance.dbInstanceEndpointAddress,
        DB_PORT: '5432',
        DB_NAME: 'appdb',
      },
    });

    // Allow Lambda to connect to RDS
    dbInstance.grantConnect(lambdaFunction);

    // Allow Lambda to retrieve RDS secret
    const secret = dbInstance.secret;
    if (secret) {
      secret.grantRead(lambdaFunction);
    }

    new cdk.CfnOutput(this, 'LambdaFunctionArn', {
      value: lambdaFunction.functionArn,
      exportName: 'ComputeStack-LambdaArn',
    });
  }
}

App Integration (bin/main.ts):

import * as cdk from 'aws-cdk-lib';
import { NetworkStack } from '../lib/network-stack';
import { DatabaseStack } from '../lib/database-stack';
import { ComputeStack } from '../lib/compute-stack';

const app = new cdk.App();

const networkStack = new NetworkStack(app, 'NetworkStack', {
  env: { region: 'us-east-1' },
});

const databaseStack = new DatabaseStack(app, 'DatabaseStack', networkStack.vpc, {
  env: { region: 'us-east-1' },
});

const computeStack = new ComputeStack(
  app,
  'ComputeStack',
  networkStack.vpc,
  databaseStack.dbInstance,
  { env: { region: 'us-east-1' } }
);

Deploy:

cdk synth
cdk deploy NetworkStack DatabaseStack ComputeStack

Total Time: ~2 minutes (3 prompts + deployment). Cost: ~$0.50 in API calls.


Security Best Practices: Least-Privilege IAM

Claude Opus 4.6 excels at generating minimal IAM policies. Example:

Prompt: “Generate an IAM policy for a Lambda that reads from a specific S3 bucket (arn:aws:s3:::my-bucket/*) and writes logs to CloudWatch.”

Output:

const policy = new iam.PolicyStatement({
  effect: iam.Effect.ALLOW,
  actions: [
    's3:GetObject',
    'logs:CreateLogGroup',
    'logs:CreateLogStream',
    'logs:PutLogEvents',
  ],
  resources: [
    'arn:aws:s3:::my-bucket/*',
    'arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/MyFunction:*',
  ],
});

This is correct: no s3:* wildcard, specific bucket ARN, limited log operations.

ChatGPT 4o frequently suggests:

actions: ['s3:*'],  // OVERLY PERMISSIVE

When NOT to Use AI for CDK

  1. Security-critical stacks: Banking, compliance (PCI-DSS, HIPAA). Code review CDK always.
  2. Exotic constructs: Hybrid CDK + CloudFormation mixing. AI struggles with template mixing.
  3. Custom L1 constructs: Writing your own constructs requires deep CDK SDK knowledge beyond AI scope.

Final Recommendations


Cost Analysis: 12-Month Content Strategy

Generate 30 CDK stack articles (5 simple, 15 intermediate, 10 advanced):

Conclusion: Claude Opus 4.6 is the clear winner for CDK infrastructure content. Reliable, production-safe, and cost-efficient. Use ChatGPT 4o for secondary sources or educational framing. Avoid Copilot and Codeium for stack generation.