Self-Service CI/CD for AWS

Self-service AWS CodePipeline platform — developers ship compliant CI/CD pipelines in minutes via dashboard, CLI, CDK, or AI prompt, while platform teams enforce policy-as-code guardrails, governance, and per-team isolation.

CDK Usage Guide

Use the PipelineBuilder CDK construct to define pipelines as infrastructure-as-code. Pipelines deploy as native AWS CodePipeline + CodeBuild in your AWS account, with build steps drawn from a catalog of 119 ready-to-use plugins.

npm install @pipeline-builder/pipeline-core
Related docs: Metadata Keys Samples Plugin Catalog Environment Variables

Overview

This guide is for developers defining pipelines as infrastructure-as-code with the PipelineBuilder CDK construct from @pipeline-builder/pipeline-core. You declare a synth source and a set of stages whose steps reference catalog plugins, and the construct synthesizes native AWS CodePipeline + CodeBuild resources deployed into your own account. The key concept: each step is a containerized plugin, and fine-grained behavior (VPC, IAM roles, secrets, cross-account, scheduling, artifacts) is layered on through typed props and metadata keys.

Process overview

  1. Installnpm install @pipeline-builder/pipeline-core.
  2. Instantiate PipelineBuilder in a CDK stack with project and organization.
  3. Configure the synth source — GitHub, CodeStar, S3, or CodeCommit — plus the synth plugin.
  4. Define stages, each with one or more plugin-backed steps from the catalog.
  5. Layer optional config — VPC/network, IAM roles, secrets, cross-account, schedules, artifact passing, and metadata.
  6. Synth + deploy the stack (via cdk or pipeline-manager), producing native CodePipeline + CodeBuild resources.

Quick Start

import { App, Stack } from 'aws-cdk-lib';
import { PipelineBuilder } from '@pipeline-builder/pipeline-core/cdk';

const app = new App();
const stack = new Stack(app, 'MyPipelineStack', {
  env: { account: '123456789012', region: 'us-east-1' },
});

new PipelineBuilder(stack, 'MyPipeline', {
  project: 'my-app',
  organization: 'my-org',
  synth: {
    source: { type: 'github', options: { repo: 'my-org/my-app', branch: 'main' } },
    plugin: { name: 'cdk-synth', version: '1.0.0' },
  },
  stages: [
    {
      stageName: 'Test',
      steps: [{ plugin: { name: 'jest', version: '1.0.0' } }],
    },
    {
      stageName: 'Deploy',
      steps: [{ plugin: { name: 'cdk-deploy', version: '1.0.0' }, env: { ENVIRONMENT: 'production' } }],
    },
  ],
});

Prerequisite for cdk synth / cdk deploy: synth bundles the PluginLookup Lambda via NodejsFunction (esbuild). Install esbuild + pnpm (the handler’s lockfile) on PATH, or CDK falls back to Docker bundling and fails with Could not resolve "axios" / "../config/handler-constants.js": npm install -g esbuild@0.28.1 pnpm@10.33.0. See Pipeline Manager → local deploy prerequisites.


BuilderProps Reference

Property Type Required Description
project string Yes Project identifier (sanitized to lowercase alphanumeric)
organization string Yes Organization identifier
orgId string No Tenant ID for resolving per-org secrets from Secrets Manager
pipelineName string No Custom name. Default: {organization}-{project}-pipeline
synth SynthOptions Yes Synthesis step configuration (source + plugin)
stages StageOptions[] No Pipeline stages, each with one or more build steps
global MetaDataType No Metadata inherited by all steps
defaults CodeBuildDefaults No Pipeline-level CodeBuild defaults (VPC, env vars)
role RoleConfig No IAM role for the CodePipeline (omit for auto-creation)
schedule string No Cron/rate expression for scheduled execution
tags Record<string, string> No Tags applied to all pipeline resources

Source Types

GitHub

synth: {
  source: {
    type: 'github',
    options: {
      repo: 'my-org/my-app',       // Required: owner/repo
      branch: 'main',               // Default: 'main'
      trigger: TriggerType.AUTO,     // AUTO = poll for changes, NONE = manual, SCHEDULE = cron
    },
  },
  plugin: { name: 'cdk-synth' },
}

CodeStar Connection (GitHub, Bitbucket, GitLab)

source: {
  type: 'codestar',
  options: {
    repo: 'my-org/my-app',
    branch: 'main',
    connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/abc-123',
    codeBuildCloneOutput: true,   // Enable full git history in CodeBuild
    trigger: TriggerType.AUTO,    // AUTO = push-based webhook (no polling), NONE = manual
  },
}

Creating the connection

The connectionArn above refers to an AWS CodeConnections (formerly CodeStar Connections) resource you create once per Git provider, then reuse across pipelines. A brand-new connection is created in a PENDING state and only works after you finish the handshake in the console:

  1. AWS Console → Developer Tools → Settings → Connections → Create connection (or CLI: aws codeconnections create-connection --provider-type GitHub --connection-name my-app).
  2. Pick the provider — GitHub, GitHub Enterprise Server, Bitbucket, or GitLab — name it, and click Connect.
  3. Install / authorize the AWS Connector app for your Git org when prompted (GitHub: “Install a new app” → choose the org → select repos), then Connect to finish. This flips the connection from Pending to Available.
  4. Copy the connection ARN (arn:aws:codeconnections:<region>:<account>:connection/<uuid>; the legacy codestar-connections ARN form also works) into connectionArn.
  5. Ensure the pipeline/deploy role can use it — allow codeconnections:UseConnection (and codestar-connections:UseConnection) on that ARN.

A connection left in Pending (its app was never authorized) makes the Source stage fail with an access error. Authorizing the connector is a one-time, console-only step — it can’t be completed from CDK.

S3

source: {
  type: 's3',
  options: {
    bucketName: 'my-source-bucket',
    objectKey: 'source.zip',       // Default: 'source.zip'
    trigger: TriggerType.AUTO,     // Start on S3 object-change events
  },
}

CodeCommit

source: {
  type: 'codecommit',
  options: {
    repositoryName: 'my-repo',
    branch: 'main',
  },
}

Stages and Steps

Each stage contains one or more steps. Each step references a plugin.

stages: [
  {
    stageName: 'Quality',
    steps: [
      {
        plugin: { name: 'eslint', version: '1.0.0' },
        failureBehavior: 'warn',              // Don't block pipeline on lint failures
      },
      {
        plugin: { name: 'prettier', version: '1.0.0' },
        failureBehavior: 'warn',
      },
    ],
  },
  {
    stageName: 'Test',
    steps: [
      {
        plugin: { name: 'jest', version: '1.0.0' },
        timeout: 30,                           // Minutes
        env: { NODE_ENV: 'test' },
      },
    ],
  },
  {
    stageName: 'Deploy',
    steps: [
      {
        plugin: { name: 'cdk-deploy', version: '1.0.0' },
        position: 'post',                     // Run after stage deployment
        env: { ENVIRONMENT: 'production' },
      },
    ],
  },
],

Step Options

Property Type Description
plugin PluginOptions Plugin to run (name, version, filter)
env Record<string, string> Environment variables
timeout number Max execution time in minutes
position 'pre' \| 'post' Before or after stage deployment (default: 'pre')
failureBehavior 'fail' \| 'warn' \| 'ignore' Override plugin default
metadata MetaDataType Step-level metadata
network NetworkConfig Step-level VPC/subnet config
preInstallCommands string[] Run before plugin install commands
postInstallCommands string[] Run after plugin install commands
preCommands string[] Run before plugin build commands
postCommands string[] Run after plugin build commands
inputArtifact ArtifactKey Input from a previous step’s output

Plugin Options

plugin: {
  name: 'jest',                    // Required: registered plugin name
  version: '1.0.0',               // Pin a specific version
  alias: 'jest-unit',             // Alias for multiple uses of same plugin
  filter: {                        // Optional query filter
    accessModifier: 'public',
    isActive: true,
  },
  metadata: {                      // Plugin-level metadata overrides
    'aws:cdk:codebuild:buildenvironment:computetype': 'BUILD_GENERAL1_MEDIUM',
  },
}

VPC and Network Configuration

Pipeline-Level (applies to all CodeBuild actions)

new PipelineBuilder(stack, 'Pipeline', {
  project: 'my-app',
  organization: 'my-org',
  defaults: {
    network: {
      type: 'vpcId',
      vpcId: 'vpc-abc123',
      subnetType: 'PRIVATE_WITH_EGRESS',
    },
  },
  synth: { ... },
  stages: [ ... ],
});

Step-Level Override

stages: [{
  stageName: 'Deploy',
  steps: [{
    plugin: { name: 'cdk-deploy' },
    network: {
      type: 'subnetIds',
      vpcId: 'vpc-abc123',
      subnetIds: ['subnet-111', 'subnet-222'],
      securityGroupIds: ['sg-abc'],
    },
  }],
}],

Network Types

Type Description
subnetIds Explicit VPC ID + subnet IDs + optional security group IDs
vpcId Look up VPC by ID, select subnets by type (PRIVATE_WITH_EGRESS, PUBLIC, etc.)
vpcLookup Look up VPC by tags, select subnets by type

IAM Roles

Three levels of IAM role control:

Pipeline Role

The pipeline-level role uses codepipeline.amazonaws.com as trust principal.

new PipelineBuilder(stack, 'Pipeline', {
  role: {
    type: 'roleArn',
    roleArn: 'arn:aws:iam::123456789012:role/MyPipelineRole',
    mutable: false,
  },
  // ...
});

Step Project Role (CodeBuild)

Control the CodeBuild project’s IAM role via metadata:

steps: [{
  plugin: { name: 'cdk-deploy' },
  metadata: {
    'aws:cdk:pipelines:codebuildstep:role': JSON.stringify({
      type: 'roleArn',
      roleArn: 'arn:aws:iam::123456789012:role/MyCodeBuildRole',
    }),
  },
}],

Step Action Role (CodePipeline Action)

metadata: {
  'aws:cdk:pipelines:codebuildstep:actionrole': JSON.stringify({
    type: 'roleArn',
    roleArn: 'arn:aws:iam::123456789012:role/MyActionRole',
  }),
}
Level Config Trust Principal
Pipeline BuilderProps.role codepipeline.amazonaws.com
Step project codebuildstep:role metadata codebuild.amazonaws.com
Step action codebuildstep:actionrole metadata Pipeline’s role

Role Types

Type Description
roleArn Import existing role by ARN
roleName Import existing role by name
oidc Create new role with OIDC federated trust
codeBuildDefault Create new role with codebuild.amazonaws.com trust (steps only)

Secrets Management

Secrets are resolved from AWS Secrets Manager at build time using the org-scoped naming convention.

new PipelineBuilder(stack, 'Pipeline', {
  project: 'my-app',
  organization: 'acme',
  orgId: 'org-abc123',        // Enables per-org secret resolution
  synth: { ... },
  stages: [{
    stageName: 'Security',
    steps: [{
      plugin: {
        name: 'snyk-nodejs',    // Plugin declares: secrets: [{ name: 'SNYK_TOKEN', required: true }]
        version: '1.0.0',
      },
    }],
  }],
});

Resolution path: pipeline-builder/{orgId}/SNYK_TOKEN in Secrets Manager.

Secrets are injected as SECRETS_MANAGER-type CodeBuild environment variables — never stored in images or logs.


Cross-Account Deployments

new PipelineBuilder(stack, 'Pipeline', {
  project: 'my-app',
  organization: 'acme',
  global: {
    'aws:cdk:pipelines:codepipeline:crossaccountkeys': 'true',
  },
  synth: {
    source: {
      type: 'codestar',
      options: {
        repo: 'acme/my-app',
        connectionArn: 'arn:aws:codestar-connections:us-east-1:111111111111:connection/...',
      },
    },
    plugin: { name: 'cdk-synth' },
  },
  stages: [{
    stageName: 'Deploy-Staging',
    steps: [{
      plugin: { name: 'cdk-deploy' },
      env: {
        CDK_DEPLOY_ACCOUNT: '222222222222',
        CDK_DEPLOY_REGION: 'us-west-2',
      },
    }],
  }],
});

Scheduled Pipelines

new PipelineBuilder(stack, 'Pipeline', {
  project: 'nightly-tests',
  organization: 'acme',
  schedule: 'cron(0 2 * * ? *)',    // Run at 2 AM UTC daily
  synth: { ... },
  stages: [ ... ],
});

Or use source-level schedule trigger:

source: {
  type: 's3',
  options: {
    bucketName: 'my-bucket',
    trigger: TriggerType.SCHEDULE,
    schedule: 'rate(1 day)',
  },
}

Artifact Passing Between Steps

Pass output from one step as input to another:

stages: [
  {
    stageName: 'Build',
    steps: [{
      plugin: { name: 'nodejs', alias: 'build-app' },
      // Output goes to primaryOutputDirectory (e.g., 'dist')
    }],
  },
  {
    stageName: 'Deploy',
    steps: [{
      plugin: { name: 'cdk-deploy' },
      inputArtifact: {
        stageName: 'Build',
        stageAlias: 'Build',
        pluginName: 'nodejs',
        pluginAlias: 'build-app',
        outputDirectory: 'dist',
      },
    }],
  },
],

Metadata Keys

Metadata controls fine-grained CDK behavior. Set at global, defaults, or step level.

Common Keys

Key Values Description
codepipeline:selfmutation 'true'/'false' Pipeline self-update on code changes
codepipeline:dockerenabledforsynth 'true'/'false' Docker available during synth
codepipeline:crossaccountkeys 'true'/'false' KMS keys for cross-account
codebuildstep:timeout '30' Step timeout in minutes
buildenvironment:privileged 'true'/'false' Docker-in-Docker mode
buildenvironment:computetype 'BUILD_GENERAL1_SMALL' etc. Instance size
network:vpcid VPC ID VPC for builds
network:subnetids JSON array of subnet IDs Subnet placement
notifications:topic:arn SNS topic ARN Pipeline event notifications

See Metadata Keys for the complete list of 80 keys.


CDK Examples

Self-contained stack classes in deploy/samples/cdk/:

Sample Pattern
basic-pipeline-ts Simplest usage — GitHub source, 4 stages
vpc-isolated-pipeline-ts VPC networking with step-level overrides
multi-account-pipeline-ts Cross-account with CodeStar, ManualApproval
monorepo-pipeline-ts Monorepo with factory functions, per-service Docker
custom-iam-roles-ts Three levels of IAM role control
secrets-management-ts Secrets Manager with orgId-scoped resolution