Overview
The starter kit includes two constructs that handle environment-aware naming and common infrastructure patterns. Extend these for consistent behavior across your stacks.
Learn the fundamentals of creating AWS CDK constructs before diving into the patterns below.
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)
| Parameter | Type | Description |
|---|---|---|
scope | Construct | Parent construct scope |
id | string | Unique identifier within scope |
Properties
| Property | Type | Description |
|---|---|---|
branch | string | undefined | Cleaned branch name from GIT_BRANCH_REF. Returns undefined for main, develop, and version tags. |
environment | string | Environment name from ENVIRONMENT variable. Defaults to dev. |
account | string | AWS account ID of the current stack |
region | string | AWS region of the current stack |
Methods
unique
Generates environment or branch-suffixed resource names (max 64 characters).
unique(name: string): string
| Parameter | Type | Description |
|---|---|---|
name | string | Base 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)
| Parameter | Type | Description |
|---|---|---|
scope | Construct | Parent construct scope |
id | string | Unique identifier within scope |
Configuration by environment
| Setting | Development/Test | Production |
|---|---|---|
| CIDR | 172.16.0.0/16 (dev), 172.17.0.0/16 (test) | 172.18.0.0/16 |
| NAT Gateways | 1 | 3 |
| Availability Zones | 3 | 3 |
| Subnet size | /20 per subnet | /20 per subnet |
Resources created
| Resource | Description |
|---|---|
| VPC | Three-tier VPC with public, private, and isolated subnets |
| NAT Gateways | Environment-specific count for private subnet egress |
| Gateway Endpoints | S3 and DynamoDB endpoints included |
| Flow Logs | Stored in encrypted S3 bucket with blocked public access |
Properties
| Property | Type | Description |
|---|---|---|
vpc | ec2.Vpc | The 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,
});
}
}
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 { 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