Writing Pulumi infrastructure-as-code (IaC) requires understanding both cloud provider APIs and programmatic resource composition. AI assistants excel at this because Pulumi’s code-first approach maps well to how LLMs reason about code generation. Claude, GitHub Copilot, and Cursor each have distinct strengths when generating TypeScript and Python Pulumi programs. The key difference lies in context window size, code understanding depth, and real-time completion accuracy.
Why Pulumi IaC Is Different From Other Code
Traditional Terraform uses HCL, a declarative language specifically designed for infrastructure. Pulumi uses general-purpose languages (Python, TypeScript, Go, C#) to define infrastructure through SDK calls. This means you’re writing code that calls Pulumi provider APIs, manages state through object references, and often needs to handle cross-stack dependencies.
AI assistants trained on large codebases understand both language semantics and Pulumi SDK patterns. However, they differ significantly in:
- Context window: How much of your existing stack they can see at once
- Pulumi SDK version accuracy: Whether they generate deprecated or current API calls
- State management comprehension: Understanding stack references and outputs
- Performance optimization awareness: Whether they suggest parallel resource creation
Tool Comparison: Claude vs Copilot vs Cursor
Claude (Opus or Sonnet)
Claude excels at Pulumi IaC generation through its extended context window (200K tokens) and deep code reasoning. You can paste your entire existing stack, architecture diagrams, and AWS/GCP documentation simultaneously.
Strengths:
- 200K context window allows analyzing 20+ files of existing infrastructure
- Excellent at explaining why a specific Pulumi pattern is needed
- Strong at generating cross-stack resource references
- Handles complex dependency chains without referencing outdated patterns
Weaknesses:
- Requires explicit prompting to use latest Pulumi SDK versions
- No real-time IDE integration without third-party tools
- Slower response times than lighter models
Real pricing: Claude API: $3/1M input tokens, $15/1M output tokens (Opus). For a 50,000-token infrastructure context: ~$0.15 input cost.
Example prompt pattern:
I have a TypeScript Pulumi stack that creates:
1. VPC with 3 subnets across 2 AZs
2. RDS Aurora cluster
3. ECS cluster with service discovery
[Paste full existing Pulumi code here]
Now I need to add a Lambda function that reads from the Aurora cluster and publishes metrics to CloudWatch. The Lambda needs:
- IAM role with RDS read access
- VPC subnet assignment
- CloudWatch Logs group
Generate the Pulumi TypeScript code following my existing patterns.
Claude will generate complete, idiomatic TypeScript that matches your existing code style and properly references the Aurora endpoint through stack exports.
GitHub Copilot
Copilot operates directly in your IDE and learns from your codebase. It’s optimized for velocity—quick completions and line-by-line suggestions. Copilot uses GPT-4 as its underlying model but with codebase-specific context.
Strengths:
- Real-time inline completion while typing
- Learns from your specific Pulumi patterns immediately
- Fast iteration on single functions or resources
- Works without explicit prompting
Weaknesses:
- Limited context window (~8K tokens) restricts cross-file understanding
- Often generates deprecated Pulumi APIs without explicit version control
- Struggles with complex multi-resource dependencies
- Cannot see external documentation unless you paste it
Real pricing: $10/month for individuals, $21/month for business accounts. Enterprise: custom pricing.
Practical example: You’re writing a new ECS service definition. Copilot watches your existing Pulumi patterns and suggests:
const taskRole = new aws.iam.Role("app-task-role", {
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal(
aws.iam.Principals.EcsTasksPrincipal
),
});
Copilot learns from your codebase that you use specific role naming conventions and immediately suggests completions aligned with your style.
Cursor IDE
Cursor is an AI-native IDE built on VSCode. It provides AI assistance directly in your editor with both fast completions and longer-form generation through Ctrl+K. Cursor supports multiple backend models (Claude, GPT-4, Sonnet).
Strengths:
- Full IDE integration with file navigation context
- Can read entire repository structure automatically
- Fast “Cmd+K” generation mode for larger code blocks
- Supports swapping between Claude and GPT-4 backends
- Git-aware: understands your commit history and patterns
Weaknesses:
- Requires switching IDEs (though VSCode-compatible)
- Subscription cost on top of model pricing
- Learning curve for power users comfortable with standard VSCode
Real pricing: $20/month for Cursor Pro with unlimited Claude usage.
Practical workflow:
You open your infrastructure/vpc.ts file. Cursor sees the entire project structure. You press Cmd+K and write:
Generate a cross-stack reference module that exports the VPC ID, subnet IDs,
and security group ID from the VPC stack, then show how to import and use it
in the application stack.
Cursor generates both files, understanding the project structure automatically.
Comparison Table: Capabilities Matrix
| Feature | Claude | Copilot | Cursor |
|---|---|---|---|
| Context Window | 200K tokens | 8K tokens | 50K+ (with Claude backend) |
| Pulumi SDK Accuracy | High (with explicit version mention) | Medium (often outdated) | High (with Claude backend) |
| Real-time Completion | No (requires tool) | Yes | Yes |
| Cross-file Understanding | Excellent | Poor | Excellent |
| Cost per 1000 tokens | $0.003-0.015 | $0.83/month flat | $20/month flat |
| IDE Integration | Via extension | Native | Native |
| Multi-service coordination | Excellent | Good | Excellent |
| Stack reference generation | Excellent | Fair | Excellent |
| Learning from codebase | No | Yes | Yes |
Real-World Examples: TypeScript Pulumi Generation
Example 1: VPC + RDS Stack with Network Access
Prompt to Claude:
I'm using Pulumi TypeScript to create a secure RDS PostgreSQL cluster.
Requirements:
- VPC with private subnets in 2 AZs (10.0.0.0/16)
- RDS cluster spanning both AZs
- Security group allowing PostgreSQL only from app subnets
- Output the cluster endpoint and port for cross-stack reference
- Use encryption at rest with AWS managed keys
- Enable automated backups with 7-day retention
Claude’s output (simplified):
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const vpc = new aws.ec2.Vpc("app-vpc", {
cidrBlock: "10.0.0.0/16",
enableDnsHostnames: true,
enableDnsSupport: true,
});
const privateSubnets = [];
for (let i = 0; i < 2; i++) {
const subnet = new aws.ec2.Subnet(`private-subnet-${i}`, {
vpcId: vpc.id,
cidrBlock: `10.0.${10 + i}.0/24`,
availabilityZone: aws.getAvailabilityZones({
state: "available",
}).then(azs => azs.names[i]),
});
privateSubnets.push(subnet);
}
const dbSecurityGroup = new aws.ec2.SecurityGroup("db-sg", {
vpcId: vpc.id,
ingress: [{
protocol: "tcp",
fromPort: 5432,
toPort: 5432,
securityGroups: [appSecurityGroupId], // from app stack
}],
});
const dbSubnetGroup = new aws.rds.SubnetGroup("db-subnet-group", {
subnetIds: privateSubnets.map(s => s.id),
});
const rdsCluster = new aws.rds.Cluster("postgres-cluster", {
engine: "aurora-postgresql",
engineVersion: "15.2",
databaseName: "appdb",
masterUsername: "postgres",
masterPassword: config.require("dbPassword"),
dbSubnetGroupName: dbSubnetGroup.name,
vpcSecurityGroupIds: [dbSecurityGroup.id],
storageEncrypted: true,
backupRetentionPeriod: 7,
skipFinalSnapshot: false,
finalSnapshotIdentifier: "final-snapshot-${Date.now()}",
preferredBackupWindow: "03:00-04:00",
});
export const dbEndpoint = rdsCluster.endpoint;
export const dbPort = rdsCluster.port;
This approach:
- Uses Pulumi’s AZ data source for real AZ names
- Creates proper subnet references
- Implements security group ingress rules
- Exports endpoint/port for cross-stack consumption
Example 2: ECS Service with Auto-scaling
Prompt to Claude:
Create a Pulumi TypeScript ECS service with:
- Service runs in existing VPC (pass in subnet/SG IDs from stack ref)
- Container image from ECR with tag-based updates
- Auto-scaling from 2-10 tasks based on CPU 70% threshold
- CloudWatch logs
- ALB target group attachment
- Environment variables from Secrets Manager
Assume previous stack exports dbEndpoint and dbPassword.
Result pattern (key sections):
const dbStackRef = new pulumi.StackReference("prod/db");
const dbEndpoint = dbStackRef.getOutput("dbEndpoint");
const dbPassword = dbStackRef.getOutput("dbPassword");
const taskExecutionRole = new aws.iam.Role("ecs-task-exec-role", {
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({
Service: "ecs-tasks.amazonaws.com",
}),
});
const taskRole = new aws.iam.Role("ecs-task-role", {
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({
Service: "ecs-tasks.amazonaws.com",
}),
});
// Attach policy to read from Secrets Manager
new aws.iam.RolePolicyAttachment("task-secrets", {
role: taskRole,
policyArn: "arn:aws:iam::aws:policy/SecretsManagerReadWrite",
});
const taskDefinition = new aws.ecs.TaskDefinition("app-task", {
family: "app",
networkMode: "awsvpc",
requiresCompatibilities: ["FARGATE"],
cpu: "256",
memory: "512",
executionRoleArn: taskExecutionRole.arn,
taskRoleArn: taskRole.arn,
containerDefinitions: pulumi.output([{
name: "app",
image: ecr.image.imageUri,
portMappings: [{
containerPort: 8080,
hostPort: 8080,
protocol: "tcp",
}],
environment: [
{ name: "DB_HOST", value: dbEndpoint },
{ name: "LOG_LEVEL", value: "info" },
],
logConfiguration: {
logDriver: "awslogs",
options: {
"awslogs-group": cloudwatchLogGroup.name,
"awslogs-region": aws.getRegion().then(r => r.name),
"awslogs-stream-prefix": "ecs",
},
},
}]).apply(JSON.stringify),
});
const service = new aws.ecs.Service("app-service", {
cluster: clusterArn,
taskDefinition: taskDefinition.arn,
desiredCount: 2,
launchType: "FARGATE",
networkConfiguration: {
subnets: subnetIds,
securityGroups: [sgId],
assignPublicIp: false,
},
loadBalancers: [{
targetGroupArn: targetGroupArn,
containerName: "app",
containerPort: 8080,
}],
});
const autoscaling = new aws.appautoscaling.Target("ecs-autoscaling", {
maxCapacity: 10,
minCapacity: 2,
resourceId: pulumi.interpolate`service/${clusterName}/${service.name}`,
scalableDimension: "ecs:service:DesiredCount",
serviceNamespace: "ecs",
});
new aws.appautoscaling.Policy("cpu-scaling", {
policyType: "TargetTrackingScaling",
resourceId: autoscaling.resourceId,
scalableDimension: autoscaling.scalableDimension,
serviceNamespace: autoscaling.serviceNamespace,
targetTrackingScalingPolicyConfiguration: {
predefinedMetricSpecification: {
predefinedMetricType: "ECSServiceAverageCPUUtilization",
},
targetValue: 70.0,
},
});
Claude generates complete, production-ready patterns including proper IAM roles, cross-stack references, and auto-scaling thresholds.
Practical Workflow: Which Tool for Which Task
Use Claude When:
- Designing large infrastructure (5+ interconnected stacks)
- You need to paste existing infrastructure and reason about it
- Generating complex cross-service patterns (multi-region, disaster recovery)
- You want detailed explanation of “why” certain patterns exist
- Cost: $0.50-2.00 per large infrastructure generation
Use Copilot When:
- Writing individual resources within existing patterns
- You need real-time completion while typing
- Your team already has the patterns established
- Speed over explanation matters
- Cost: Fixed $10-21/month regardless of usage
Use Cursor When:
- You want IDE-integrated AI with full project context
- Generating multiple files simultaneously
- You want to learn from your own codebase patterns
- You’re switching IDEs anyway
- Cost: $20/month for unlimited Claude usage
CLI Commands for Pulumi Workflow
Deploy and preview your generated code:
# Initialize a new Pulumi project
pulumi new aws-typescript
# Preview changes before deployment
pulumi preview --stack prod
# Deploy infrastructure
pulumi up --stack prod
# Refresh stack state (useful after manual changes)
pulumi refresh --stack prod
# Destroy infrastructure
pulumi destroy --stack prod
# List stack references available to other stacks
pulumi stack select prod
pulumi stack export
Decision Framework: Accuracy vs Velocity
Ask yourself these questions:
- How large is the infrastructure change? (1-2 resources vs entire new stack)
- Small: Use Copilot for velocity
- Large: Use Claude for accuracy
- Do you need to reference existing infrastructure?
- Yes, across many stacks: Claude’s context window wins
- No, isolated resources: Copilot/Cursor sufficient
- Is your team already on a specific IDE?
- Already on VSCode: Cursor eliminates friction
- Different editors: Claude API is universal
- What’s your error tolerance?
- Low (production): Claude with explicit version pinning
- Medium (staging): Copilot is acceptable
- High (dev): Any tool with quick iteration
- How often do you write IaC?
- Daily: Cursor ($20/month) pays for itself
- Weekly: Claude ($3-5/week API cost) more economical
- Monthly: Copilot ($10/month) simplest
Common Mistakes AI Tools Make
All three tools occasionally generate:
- Deprecated Pulumi APIs: Always specify
@pulumi/aws@6.0.0or later in prompts - Missing IAM policies: AI suggests resource creation but omits role/policy attachment
- Hardcoded values: Wrap environment-specific values in
config.require() - Missing cross-stack exports: Prompt explicitly: “What should I export from this stack?”
- Insufficient error handling: Pulumi imports can fail; AI doesn’t always add try-catch
Testing Generated Infrastructure Code
Before deploying generated Pulumi code:
# Lint TypeScript
npx tsc --noEmit
# Validate stack can be serialized
pulumi preview --verbose
# Check for unused variables
npm run lint
# Test stack references in isolation
pulumi stack ls
pulumi stack select staging
pulumi stack export > export.json
Cost Comparison: Per-Project Basis
For a typical infrastructure project (5 stacks, ~1000 lines total):
| Tool | Cost for Project | Cost per Year |
|---|---|---|
| Claude (API) | $5-15 | $60-180 |
| Copilot | $10/month | $120 |
| Cursor | $20/month | $240 |
| Multiple tools combined | $10-20 | $120-240 |
Most teams find combined approach optimal: Cursor for daily editing, Claude for complex designs, Copilot as fallback.
Related Articles
- Best AI Assistants for Pulumi Infrastructure Code
- Claude vs Gpt4 Terraform Pulumi Infrastructure Code
- AI Tools for Writing Terraform Infrastructure-as-Code
- Best AI Tools for Writing AWS CDK Infrastructure Code
- Best Workflow for Using AI to Write Infrastructure as Code F
Built by theluckystrike — More at zovo.one