Use Cases (Updated: 6/1/2026)

Claude Code and AWS CodePipeline: stages, artifacts, approvals, and safe deploys

Design AWS CodePipeline with Claude Code: stages, actions, artifacts, CodeBuild, approvals, S3, Lambda, and failure checks.

Claude Code and AWS CodePipeline: stages, artifacts, approvals, and safe deploys

“Why bother with AWS CodePipeline when GitHub Actions works fine?”—a question I hear all the time.

The answer lies in deep integration with AWS resources. Pushing to ECR, deploying to ECS, updating CloudFormation stacks—when you want all of this to work natively within AWS, CodePipeline + CodeBuild is the most seamless combination.

I manage pipelines that combine multiple AWS services at work, and ever since Claude Code started generating buildspec.yml, CDK code, and IAM policies all at once just from describing my pipeline requirements, the time to build new pipelines has dropped to one-quarter of what it used to be.


Basic Structure of CodePipeline / CodeBuild

CodePipeline (Orchestrator)
    │
    ├─ Source Stage:  Fetch code from GitHub / CodeCommit
    ├─ Build Stage:   Build, test, create Docker images with CodeBuild
    ├─ Test Stage:    Integration tests, security scans (optional)
    └─ Deploy Stage:  Deploy to ECS / Elastic Beanstalk / S3

CodeBuild executes commands written in buildspec.yml. Think of it as the equivalent of steps: in GitHub Actions.


Step 1: Auto-Generate buildspec.yml

claude -p "
Generate a buildspec.yml for CodeBuild with the following requirements.

[Build Contents]
- Node.js 20 environment
- Install with npm ci
- TypeScript build (npm run build)
- Run unit tests (npm test)
- Build Docker image and push to ECR
- Image tag: CODEBUILD_RESOLVED_SOURCE_VERSION (Git SHA)
- Also attach latest tag simultaneously

[Security Scan]
- Run Trivy scan after ECR image push
- Fail build if HIGH/CRITICAL vulnerabilities found

[Artifacts]
- Output imagedefinitions.json (for ECS deploy)
"

Generated buildspec.yml:

version: 0.2

env:
  variables:
    AWS_DEFAULT_REGION: us-east-1
    ECR_REPO_NAME: myapp
  parameter-store:
    ECR_REGISTRY: /myapp/ecr-registry

phases:
  install:
    runtime-versions:
      nodejs: 20
    commands:
      - echo "Installing dependencies..."
      - npm ci

  pre_build:
    commands:
      - echo "Running tests..."
      - npm test
      - echo "Logging in to Amazon ECR..."
      - aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REGISTRY
      - IMAGE_TAG=$CODEBUILD_RESOLVED_SOURCE_VERSION
      - IMAGE_URI=$ECR_REGISTRY/$ECR_REPO_NAME:$IMAGE_TAG

  build:
    commands:
      - echo "Building TypeScript..."
      - npm run build
      - echo "Building Docker image..."
      - docker build -t $IMAGE_URI -t $ECR_REGISTRY/$ECR_REPO_NAME:latest .

  post_build:
    commands:
      - echo "Pushing image to ECR..."
      - docker push $IMAGE_URI
      - docker push $ECR_REGISTRY/$ECR_REPO_NAME:latest
      - echo "Scanning image for vulnerabilities..."
      - |
        docker run --rm \
          -v /var/run/docker.sock:/var/run/docker.sock \
          aquasec/trivy:latest image \
          --exit-code 1 \
          --severity HIGH,CRITICAL \
          $IMAGE_URI
      - echo "Creating imagedefinitions.json..."
      - printf '[{"name":"app","imageUri":"%s"}]' $IMAGE_URI > imagedefinitions.json

artifacts:
  files:
    - imagedefinitions.json

reports:
  test-reports:
    files:
      - "coverage/junit.xml"
    file-format: JUNITXML

Step 2: Build the Entire Pipeline with CDK

claude -p "
Implement the following CodePipeline in CDK TypeScript in lib/pipeline-stack.ts.

[Pipeline Configuration]
- Source: GitHub (main branch of owner/repo)
- Build: CodeBuild (using buildspec.yml above)
- Deploy: Blue/Green deployment to ECS service

[Notifications]
- Notify Slack via SNS on pipeline failure
- Also notify Slack on successful deployment

[Artifact Store]
- S3 bucket (encryption and versioning enabled)
"
// lib/pipeline-stack.ts
import * as cdk from "aws-cdk-lib";
import * as codepipeline from "aws-cdk-lib/aws-codepipeline";
import * as codepipeline_actions from "aws-cdk-lib/aws-codepipeline-actions";
import * as codebuild from "aws-cdk-lib/aws-codebuild";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as iam from "aws-cdk-lib/aws-iam";
import * as sns from "aws-cdk-lib/aws-sns";
import * as ecs from "aws-cdk-lib/aws-ecs";

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

    // Artifact store S3 bucket
    const artifactBucket = new s3.Bucket(this, "ArtifactBucket", {
      versioned: true,
      encryption: s3.BucketEncryption.S3_MANAGED,
      removalPolicy: cdk.RemovalPolicy.RETAIN,
    });

    // Artifact definitions
    const sourceOutput = new codepipeline.Artifact("SourceOutput");
    const buildOutput = new codepipeline.Artifact("BuildOutput");

    // CodeBuild project
    const buildProject = new codebuild.PipelineProject(this, "BuildProject", {
      buildSpec: codebuild.BuildSpec.fromSourceFilename("buildspec.yml"),
      environment: {
        buildImage: codebuild.LinuxBuildImage.STANDARD_7_0,
        privileged: true,  // Required for Docker builds
      },
      environmentVariables: {
        AWS_ACCOUNT_ID: { value: this.account },
      },
    });

    // Grant ECR access permissions
    buildProject.addToRolePolicy(new iam.PolicyStatement({
      actions: [
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:PutImage",
        "ecr:InitiateLayerUpload",
        "ecr:UploadLayerPart",
        "ecr:CompleteLayerUpload",
      ],
      resources: ["*"],
    }));

    // Pipeline
    const pipeline = new codepipeline.Pipeline(this, "Pipeline", {
      pipelineName: "myapp-pipeline",
      artifactBucket,
      stages: [
        {
          stageName: "Source",
          actions: [
            new codepipeline_actions.GitHubSourceAction({
              actionName: "GitHub_Source",
              owner: "your-org",
              repo: "your-repo",
              branch: "main",
              oauthToken: cdk.SecretValue.secretsManager("github-token"),
              output: sourceOutput,
            }),
          ],
        },
        {
          stageName: "Build",
          actions: [
            new codepipeline_actions.CodeBuildAction({
              actionName: "Build_and_Test",
              project: buildProject,
              input: sourceOutput,
              outputs: [buildOutput],
            }),
          ],
        },
        {
          stageName: "Deploy",
          actions: [
            new codepipeline_actions.EcsDeployAction({
              actionName: "Deploy_to_ECS",
              service: ecs.FargateService.fromFargateServiceAttributes(
                this, "EcsService", {
                  cluster: ecs.Cluster.fromClusterArn(
                    this, "Cluster",
                    `arn:aws:ecs:${this.region}:${this.account}:cluster/myapp-cluster`
                  ),
                  serviceName: "myapp-service",
                }
              ),
              input: buildOutput,
            }),
          ],
        },
      ],
    });

    // Failure notifications
    const alertTopic = new sns.Topic(this, "AlertTopic");
    pipeline.notifyOnAnyStageStateChange("PipelineNotification", alertTopic, {
      events: [
        codepipeline.PipelineNotificationEvents.PIPELINE_EXECUTION_FAILED,
        codepipeline.PipelineNotificationEvents.PIPELINE_EXECUTION_SUCCEEDED,
      ],
    });
  }
}

Step 3: Configure Test Result Reports

claude -p "
I want to send test results to CodeBuild Reports in CodeBuild
so I can check quality reports per PR.

- Test framework: Vitest
- Coverage report: Istanbul (lcov format)
- Add reports section to buildspec.yml
- Also define report group with CDK
"
# buildspec.yml reports section
reports:
  UnitTestResults:
    files:
      - "test-results/junit.xml"
    file-format: JUNITXML
  CodeCoverage:
    files:
      - "coverage/lcov.info"
    file-format: CLOVERXML

Step 4: Multi-Environment Pipeline Design

claude -p "
Design a CDK staged deployment pipeline for 3 environments: dev → staging → prod.

- dev: auto-deploy on push to main branch
- staging: deploy after dev succeeds, with manual approval
- prod: deploy after staging succeeds, with manual approval
- Notify Slack when each environment deployment completes
"
// Add manual approval gates for staging → prod
{
  stageName: "Approve_Staging",
  actions: [
    new codepipeline_actions.ManualApprovalAction({
      actionName: "Approve_Deploy_to_Staging",
      notificationTopic: alertTopic,
      additionalInformation: "Do you approve deployment to Staging?",
    }),
  ],
},
{
  stageName: "Deploy_Staging",
  actions: [
    new codepipeline_actions.EcsDeployAction({
      actionName: "Deploy_to_Staging",
      service: stagingService,
      input: buildOutput,
    }),
  ],
},

4 Common Pitfalls

1. Forgetting privileged: true in CodeBuild

Building Docker images requires privileged: true. Without it, you’ll get Cannot connect to the Docker daemon errors.

2. Insufficient GitHub OAuth Token Permissions

The GitHub source requires the repo scope. Using only public_repo won’t work for private repositories.

3. S3 Artifact Bucket Region

The pipeline and the artifact S3 bucket must be in the same region. Cross-region pipelines require additional configuration.

4. imagedefinitions.json Format for ECS Deploy Action

ECS deployment requires the exact format:

[{"name": "container-name", "imageUri": "image-uri"}]

The container name must exactly match the container name in the task definition.


Start with the minimal Source-Build-Test-Deploy shape

For a beginner, CodePipeline is easiest to understand as a conveyor belt for releases. A pipeline is the whole release flow. A stage is a named section such as Source, Build, Test, Approval, or Deploy. An action is the actual task inside a stage. An artifact is the bundle passed from one action to the next, for example source code from GitHub or a built dist directory from CodeBuild.

The AWS CodePipeline concepts page uses the same mental model: pipelines contain stages, stages contain actions, and actions consume or produce artifacts. When you ask Claude Code to build a pipeline, naming these four pieces clearly prevents vague and risky output.

A practical first pipeline is Source -> Build -> Test -> Approve -> Deploy. AWS notes in the pipeline creation guide that a pipeline needs at least a source stage and one other build or deployment stage. In real teams, adding a manual approval before production is usually worth the extra click because it gives humans one final checkpoint.

stageactionartifactpurpose
SourceGitHub / CodeStar connectionSourceOutputPull the main branch change
BuildCodeBuildBuildOutputnpm ci, tests, build, zip
TestCodeBuildTestOutputRun smoke tests separately
ApproveManual approvalnoneHuman check before production
DeployS3 / CloudFormation / LambdaBuildOutputPublish to S3/CloudFront or Lambda
{
  "pipeline": {
    "name": "webapp-main",
    "roleArn": "arn:aws:iam::123456789012:role/service-role/AWSCodePipelineServiceRole-ap-northeast-1-webapp-main",
    "artifactStore": { "type": "S3", "location": "my-codepipeline-artifacts-apne1" },
    "stages": [
      { "name": "Source", "actions": [{ "name": "Source", "actionTypeId": { "category": "Source", "owner": "AWS", "provider": "CodeStarSourceConnection", "version": "1" }, "configuration": { "ConnectionArn": "arn:aws:codestar-connections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "FullRepositoryId": "your-org/your-repo", "BranchName": "main", "OutputArtifactFormat": "CODE_ZIP" }, "outputArtifacts": [{ "name": "SourceOutput" }], "runOrder": 1 }] },
      { "name": "Build", "actions": [{ "name": "BuildAndUnitTest", "actionTypeId": { "category": "Build", "owner": "AWS", "provider": "CodeBuild", "version": "1" }, "configuration": { "ProjectName": "webapp-build" }, "inputArtifacts": [{ "name": "SourceOutput" }], "outputArtifacts": [{ "name": "BuildOutput" }], "runOrder": 1 }] },
      { "name": "ApproveProd", "actions": [{ "name": "ApproveProduction", "actionTypeId": { "category": "Approval", "owner": "AWS", "provider": "Manual", "version": "1" }, "configuration": { "CustomData": "Check smoke test, CloudWatch alarms, and release note before approving." }, "runOrder": 1 }] }
    ]
  }
}
aws codepipeline create-pipeline --cli-input-json file://pipeline.json
aws codepipeline get-pipeline --name webapp-main
aws codepipeline start-pipeline-execution --name webapp-main

S3/CloudFront and Lambda deploy examples

For a static site, let CodeBuild create the dist directory and let the S3 deploy action extract the artifact into the hosting bucket. CloudFront invalidation is a separate concern, so put it in a following CodeBuild or Lambda invoke action if you want the pipeline graph to stay readable. For Lambda, CodeBuild can package the function and CloudFormation can deploy the packaged template.

version: 0.2

env:
  variables:
    AWS_REGION: ap-northeast-1
    S3_BUCKET: my-webapp-prod
    CLOUDFRONT_DISTRIBUTION_ID: E1234567890ABC

phases:
  install:
    runtime-versions:
      nodejs: 20
    commands:
      - npm ci
  pre_build:
    commands:
      - npm test
      - npm run lint
  build:
    commands:
      - npm run build
  post_build:
    commands:
      - aws s3 sync ./dist s3://$S3_BUCKET/ --delete --cache-control "public,max-age=300"
      - aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_DISTRIBUTION_ID --paths "/*"

artifacts:
  base-directory: dist
  files:
    - "**/*"

For Lambda, keep the package and the deploy template visible as artifacts.

version: 0.2

env:
  variables:
    AWS_REGION: ap-northeast-1
    ARTIFACT_BUCKET: my-lambda-artifacts-apne1

phases:
  install:
    runtime-versions:
      nodejs: 20
    commands:
      - npm ci
  build:
    commands:
      - npm test
      - npm run build
      - zip -r function.zip dist package.json node_modules
  post_build:
    commands:
      - aws s3 cp function.zip s3://$ARTIFACT_BUCKET/lambda/function.zip
      - aws cloudformation package --template-file template.yml --s3-bucket $ARTIFACT_BUCKET --output-template-file packaged.yml

artifacts:
  files:
    - packaged.yml
    - function.zip

Three use cases cover most early teams: a static Astro or Next.js site deployed to S3 and CloudFront, a Lambda API packaged through CloudFormation, and a team release flow where staging is automatic but production requires approval. Keeping these separate makes artifacts and IAM easier to review.

How to inspect failures

When CodePipeline fails, do not stare at the whole pipeline first. Identify the failed stage and action. Source failures usually mean connection ARN, branch name, or artifact format. Build failures usually mean CodeBuild logs, buildspec syntax, environment variables, or IAM. Deploy failures usually mean artifact names, bucket permissions, CloudFormation role permissions, Lambda package paths, or region mismatch.

aws codepipeline get-pipeline-state --name webapp-main
aws codepipeline list-action-executions --pipeline-name webapp-main --max-results 5
aws codebuild batch-get-builds --ids webapp-build:BUILD_ID_FROM_ACTION_EXECUTION
aws logs tail /aws/codebuild/webapp-build --since 30m --follow

The most common artifact mistake is producing BuildOutput and then configuring the deploy action to read SourceOutput. The next one is giving the CodeBuild service role too little access to S3, CloudFront, CloudFormation, or Lambda. Another expensive mistake is placing tokens in plaintext environment variables instead of Parameter Store or Secrets Manager. AWS lists Source, Build, Test, Deploy, Approval, and Invoke as action categories in the actions guide, so review permissions by action instead of by pipeline as a whole.

A safe Claude Code prompt

Claude Code can generate a broad IAM policy or skip the approval gate if the request is too vague. The prompt should include the desired stages, the forbidden behavior, and the verification commands.

Add AWS CodePipeline + CodeBuild CI/CD to this repository.

Goal:
- Source: GitHub main
- Build: CodeBuild runs npm ci, npm test, npm run build
- Test: run smoke tests in a separate CodeBuild action
- Approve: add Manual approval before production
- Deploy: publish dist to S3 and invalidate CloudFront

Constraints:
- Do not attach AdministratorAccess or broad wildcard IAM permissions
- Do not deploy to production automatically without approval
- Do not store secrets in plaintext environment variables
- Do not delete existing pipelines or buckets

Deliverables:
- buildspec.yml
- pipeline.json or CDK stack
- failure inspection commands
- README operating guide

Verification:
- Explain the current setup before changing it
- Show the diff before applying changes
- Document aws codepipeline get-pipeline-state and CodeBuild log checks

This prompt follows the AWS pipeline creation guide and pipeline definition guide. Asking Claude Code to explain which official concepts it used makes the review much easier.

Masa-style verification note and next step

The strongest small habit is naming artifacts consistently: SourceOutput, BuildOutput, and TestOutput. That alone makes failures easier to inspect. Starting with a visible JSON or console pipeline also helps beginners map the CodePipeline screen back to the source. After the first working pipeline, CDK is much easier to understand.

This topic connects directly to IAM, S3, Lambda, and CloudFront. Read the AWS IAM guide, the AWS S3 guide, and the AWS Lambda guide if you want the whole release flow to make sense.

If you are testing alone, start with the free PDF and keep the basic Claude Code commands nearby. If you are introducing CI/CD to a team, design buildspec, IAM, approval gates, rollback behavior, and incident checks together. For that deeper setup, the Claude Code training and consultation page is the natural next step.

Summary

TaskClaude Code’s Contribution
buildspec.yml generationGenerated with build, test, Docker, and security scan included
CDK PipelineAuto-generates all stages from Source→Build→Deploy
Multi-environment designDesigns staged deployment with manual approval gates
Test reportsAutomates CodeBuild Reports configuration

CodePipeline configuration may look complex, but just tell Claude Code “I want this kind of pipeline” and it will produce both buildspec.yml and CDK code in one shot. Start by trying it with buildspec.yml first.

References

#claude-code #aws #codepipeline #codebuild #cicd #devops
Free

Free PDF: Claude Code Cheatsheet

Enter your email and download the one-page Claude Code cheatsheet for commands, review habits, and safe workflows.

We handle your data with care and never send spam.

Level up your Claude Code workflow

Start with the free PDF, use Gumroad guides when you need repeatable workflows, and book consultation when rollout or revenue paths need human judgment.

Masa

About the Author

Masa

Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.