Add resources to the starter stack
The quickest way to begin is by extending StarterStack
in src/stacks/starter-stack.ts
.
// src/stacks/starter-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';
export class StarterStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: cdk.StackProps) {
super(scope, id, props);
new s3.Bucket(this, 'ArtifactsBucket', {
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
versioned: true,
encryption: s3.BucketEncryption.S3_MANAGED,
});
}
}
Tagging, naming, and branch-awareness are already handled in src/main.ts
, so resources you add here inherit the environment tags configured in the app.
Add a new stack alongside the starter stack
- Create
src/stacks/app-stack.ts
with your newStack
implementation. - Export it from
src/stacks/index.ts
. - Instantiate it in
src/main.ts
usingcreateEnvResourceName
to keep names branch-aware.
// src/stacks/app-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class AppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Add resources here
}
}
// src/stacks/index.ts
export { AppStack } from './app-stack';
// src/main.ts (imports above omitted for brevity)
import { AppStack } from './stacks';
new AppStack(app, createEnvResourceName('AppStack'), { env: awsAccountConfig });
Run npm run test:synth
(or swap test
for another environment) to confirm the new stack synthesizes cleanly before deploying.
Compose constructs for reuse
Create constructs under src/constructs/
and extend BaseConstruct
to gain environment, account, region, and branch helpers.
// src/constructs/storage-bucket.ts
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';
import { BaseConstruct } from './base-construct';
export class StorageBucket extends BaseConstruct {
public readonly bucket: s3.Bucket;
constructor(scope: Construct, id: string, props?: s3.BucketProps) {
super(scope, id);
this.bucket = new s3.Bucket(this, 'Bucket', {
bucketName: this.unique('artifacts'),
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
encryption: s3.BucketEncryption.S3_MANAGED,
...props,
});
}
}
Use the construct inside any stack:
import { StorageBucket } from '../constructs';
new StorageBucket(this, 'ArtifactsBucket', { versioned: true });
Bring in the opinionated VPC
NetworkConstruct
provisions a three-tier VPC with environment-specific CIDRs, endpoints, and flow logs. Uncomment and customize it inside StarterStack
or another stack:
import { NetworkConstruct } from '../constructs';
const network = new NetworkConstruct(this, 'Network');
// network.vpc is available for ECS clusters, RDS, etc.
Because NetworkConstruct
inherits from BaseConstruct
, VPC names and the flow-log bucket automatically include environment or branch suffixes, keeping parallel deployments isolated.
Use branch-specific stack actions locally
All environment tasks have branch variants. This makes it easy to preview infrastructure changes without affecting shared stacks:
git checkout -b feature/cost-reduction
npm run test:branch:deploy:stack StarterStack
npm run test:branch:destroy:stack StarterStack
Branch deploy tasks set GIT_BRANCH_REF
, so stack names and resource tags include the cleaned branch suffix. The Environments
guide covers the workflow end to end.