AWS CDK Starter Kit

Constructs

Reusable constructs provided by the AWS CDK Starter Kit including BaseConstruct, NetworkConstruct, and GitHubActionsOidcConstruct.

Overview

The starter kit includes three constructs: two that handle environment-aware naming and common infrastructure patterns, plus one that wires up GitHub Actions OIDC access for keyless deployments. Extend the base constructs for consistent behavior across your stacks.

Learn the fundamentals of creating AWS CDK constructs before diving into the patterns below.

Mermaid diagram loading.BaseConstruct NetworkConstruct extends BaseConstruct Your Constructs extend BaseConstruct GitHubActionsOidcConstruct

BaseConstruct

Source: src/constructs/base-construct.ts

Base class that exposes environment context and safe naming helpers. All custom constructs should extend this class.

Constructor

new BaseConstruct(scope: Construct, id: string)
ParameterTypeDescription
scopeConstructParent construct scope
idstringUnique identifier within scope

Properties

PropertyTypeDescription
branchstring | undefinedCleaned branch name from GIT_BRANCH_REF. Returns undefined for main, develop, and version tags.
environmentstringEnvironment name from ENVIRONMENT variable. Defaults to dev.
accountstringAWS account ID of the current stack
regionstringAWS region of the current stack

Methods

unique

Generates environment or branch-suffixed resource names (max 64 characters).

unique(name: string): string
ParameterTypeDescription
namestringBase name for the resource

Returns: Suffixed resource name like data-123456789012-test or data-123456789012-feature-auth.

Usage example

import { Construct } from 'constructs';
import { BaseConstruct } from '../constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';

export class DataBucketConstruct extends BaseConstruct {
  public readonly bucket: s3.Bucket;

  constructor(scope: Construct, id: string) {
    super(scope, id);

    // Environment-aware bucket name
    this.bucket = new s3.Bucket(this, 'Bucket', {
      bucketName: this.unique(`data-${this.account}`),
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
    });

    // Conditional logic based on environment
    if (this.environment === 'production') {
      this.bucket.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN);
    }
  }
}

NetworkConstruct

Source: src/constructs/network-construct.ts

Creates an opinionated VPC with environment-specific configuration. Includes public, private, and isolated subnets plus gateway endpoints and flow logs.

Constructor

new NetworkConstruct(scope: Construct, id: string)
ParameterTypeDescription
scopeConstructParent construct scope
idstringUnique identifier within scope

Configuration by environment

SettingDevelopment/TestProduction
CIDR172.16.0.0/16 (dev), 172.17.0.0/16 (test)172.18.0.0/16
NAT Gateways13
Availability Zones33
Subnet size/20 per subnet/20 per subnet

Resources created

ResourceDescription
VPCThree-tier VPC with public, private, and isolated subnets
NAT GatewaysEnvironment-specific count for private subnet egress
Gateway EndpointsS3 and DynamoDB endpoints included
Flow LogsStored in encrypted S3 bucket with blocked public access

Properties

PropertyTypeDescription
vpcec2.VpcThe created VPC instance

Usage example

import { NetworkConstruct } from '../constructs';

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

    const network = new NetworkConstruct(this, 'Network');

    // Use the VPC for other resources
    new ecs.Cluster(this, 'Cluster', {
      vpc: network.vpc,
    });
  }
}

GitHubActionsOidcConstruct

Source: src/constructs/github-actions-oidc-construct.ts

Creates a GitHub Actions OpenID Connect (OIDC) provider and an IAM deployment role so workflows can deploy to AWS without long-lived credentials. FoundationStack already uses this construct, so you rarely instantiate it directly, but it works standalone when you need a dedicated deployment role.

Constructor

new GitHubActionsOidcConstruct(scope: Construct, id: string, props: GitHubActionsOidcConstructProps)

GitHubActionsOidcConstructProps

PropertyTypeRequiredDescription
environmentstringYesGitHub environment name allowed to assume the role. The trust policy is scoped to repo:<owner>/<repo>:environment:<environment>.
additionalRepositoriesstring[]NoExtra repository names, under the same GitHub owner, allowed to assume the role. Provide bare names like my-cdk-app. Defaults to only the current git remote repo.
maxSessionDurationcdk.DurationNoMaximum session duration for the deployment role. Defaults to cdk.Duration.hours(2).
roleNamestringNoName of the IAM role. Defaults to process.env.GITHUB_DEPLOY_ROLE or GitHubActionsServiceRole.

Resources created

ResourceTypeDescription
OIDC Provideriam.OpenIdConnectProviderTrusts token.actions.githubusercontent.com with client ID sts.amazonaws.com
Deployment roleiam.RoleAssumed via GitHub OIDC, attached AdministratorAccess, scoped to the environment and repositories

Properties

PropertyTypeDescription
provideriam.OpenIdConnectProviderThe GitHub Actions OIDC identity provider
roleiam.RoleThe IAM role assumed by GitHub Actions workflows

The GitHub owner and repository name are resolved automatically from the current git remote (git config --get remote.origin.url), so no manual configuration is needed for the primary repository.

Usage example

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { GitHubActionsOidcConstruct } from '../constructs';

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

    new GitHubActionsOidcConstruct(this, 'GitHubActionsOidc', {
      environment: 'production',
      maxSessionDuration: cdk.Duration.hours(1),
    });
  }
}

Creating custom constructs

Follow this pattern when building your own constructs:

// src/constructs/my-construct.ts
import { Construct } from 'constructs';
import { BaseConstruct } from './base-construct';

export interface MyConstructProps {
  readonly featureEnabled?: boolean;
}

export class MyConstruct extends BaseConstruct {
  constructor(scope: Construct, id: string, props?: MyConstructProps) {
    super(scope, id);

    // Access inherited properties
    console.log(`Environment: ${this.environment}`);
    console.log(`Branch: ${this.branch ?? 'none'}`);

    // Use unique() for resource names
    const resourceName = this.unique('my-resource');
  }
}

Export from index:

// src/constructs/index.ts
export { BaseConstruct } from './base-construct';
export { GitHubActionsOidcConstruct } from './github-actions-oidc-construct';
export { NetworkConstruct } from './network-construct';
export { MyConstruct } from './my-construct';

Next steps

  • Aspects - Add governance rules to your constructs
  • Stacks - See how constructs are used in stacks
  • Usage Examples - Common patterns and recipes