Overview
This guide covers the essential commands and workflows for developing CDK infrastructure on your local machine before pushing to CI/CD. Everything runs through Projen-generated pnpm scripts, so the same commands work locally and in your pipelines.
Daily development cycle
The typical workflow for making infrastructure changes:
# 1. Create a feature branch
git checkout -b feature/add-lambda
# 2. Make changes to your stacks in src/stacks/
# Edit stack definitions, constructs, etc.
# 3. Build and lint
pnpm run build
# 4. Synthesize CloudFormation templates
pnpm run test:synth
# 5. Preview changes
pnpm run test:diff
# 6. Deploy changes (if diff looks good)
pnpm run test:deploy:all
# 7. Test your infrastructure
# Run manual tests or automated tests
# 8. Commit and push
git add .
git commit -m "feat: add Lambda function for processing"
git push origin feature/add-lambda
# 9. Open pull request on GitHub
Essential pnpm commands
The starter kit provides convenient pnpm scripts for all operations. Run npx projen --help to see the full list of generated tasks.
Build and test
pnpm run build # compile, synth, test, lint in one go (used by CI)
pnpm test # jest with coverage enabled
Need a faster feedback loop? Use watch mode:
pnpm run watch # rebuild and re-test on file changes
pnpm run test:watch # jest watch mode with the repo's config
Code quality
pnpm run biome # check mode (validates formatting and linting)
pnpm run biome -- --apply # fix mode (note the extra --)
Example output:
$ pnpm run biome
Checked 42 files in 0.12s. No fixes needed.
Biome rules are enforced in CI. Run them locally before you commit to avoid failed pipelines.
Environment operations
pnpm run test:synth # synthesize all stacks for the test account
pnpm run test:diff # diff all stacks against deployed state
pnpm run test:diff:stack StarterStack # diff a specific stack
pnpm run test:deploy:all # deploy all stacks
pnpm run test:deploy:stack FooStack # deploy a specific stack
pnpm run test:destroy:stack FooStack # destroy a specific stack
pnpm run test:ls # list all stacks for the environment
Important: Replace
testwith any other environment name you configure (see Configuration > Environments).
Every command sets CDK_DEFAULT_ACCOUNT, CDK_DEFAULT_REGION, ENVIRONMENT, and (for branch tasks) GIT_BRANCH_REF so names and tags stay consistent.
Branch previews
For isolated testing per feature branch:
pnpm run test:branch:synth # synthesize with branch suffix
pnpm run test:branch:diff:stack Name # diff branch-specific stack
pnpm run test:branch:deploy:all # deploy all branch stacks
pnpm run test:branch:destroy:all # cleanup when done
See Branch-based Development for the full preview workflow.
Cleanup
Always destroy branch stacks when you finish to avoid unnecessary costs:
pnpm run test:branch:destroy:all
Working with CDK directly
While pnpm scripts are convenient, you can also use CDK commands directly for more control.
Synthesize templates
npx cdk synth
npx cdk synth StarterStack # specific stack only
Generates CloudFormation templates in cdk.out/. Review these to understand exactly what CDK will deploy.
Preview changes
npx cdk diff
npx cdk diff StarterStack # specific stack only
Shows what CDK will create, modify, or destroy. Always review before deploying.
Deploy stacks
npx cdk deploy
npx cdk deploy StarterStack # specific stack only
npx cdk deploy --all # all stacks
CDK prompts for confirmation on IAM and security changes. Review carefully and type y to proceed.
Deploy with auto-approve (use with caution):
npx cdk deploy --require-approval never
Watch mode for rapid iteration
When supported by your stacks, CDK watch gives rapid redeploys:
npx cdk watch
This uses your current AWS credentials and monitors file changes. Deployments are scoped by the environment variables injected into the process. Run pnpm run test:synth once to set env vars in your shell session.
List stacks
npx cdk ls
Shows all stacks defined in your CDK app.
Destroy resources
npx cdk destroy
npx cdk destroy StarterStack # specific stack only
Destroys all resources managed by the stack. CDK prompts for confirmation.
View outputs
After deployment, stack outputs appear in the terminal. You can also query them:
aws cloudformation describe-stacks \
--stack-name StarterStack \
--query 'Stacks[0].Outputs'
Code quality checks
Biome
Run Biome for formatting and linting validation:
# From repository root
pnpm run biome
# Or fix issues automatically
pnpm run biome -- --apply
Common issues Biome catches:
- Formatting inconsistencies
- Unused imports and variables
- TypeScript best practice violations
- Consistent code style across the project
Example output:
src/stacks/starter-stack.ts:15:1: lint/style/useConst: Use 'const' instead of 'let'.
src/main.ts:8:10: lint/correctness/noUnusedImports: Remove unused import 'Duration'.
TypeScript compilation
TypeScript errors are caught during build:
pnpm run build
This runs the full compilation and will fail on type errors. Fix all TypeScript issues before committing.
Working with multiple AWS accounts
Using AWS CLI profiles
Configure profiles in ~/.aws/config:
[profile test-account]
sso_start_url = https://my-org.awsapps.com/start
sso_region = us-east-1
sso_account_id = 123456789012
sso_role_name = AdministratorAccess
region = us-east-1
[profile production-account]
sso_start_url = https://my-org.awsapps.com/start
sso_region = us-east-1
sso_account_id = 210987654321
sso_role_name = AdministratorAccess
region = us-east-1
Switch profiles:
export AWS_PROFILE=test-account
pnpm run test:deploy:all
export AWS_PROFILE=production-account
pnpm run production:deploy:all
Using Granted
Granted simplifies multi-account access:
# Install via Homebrew
brew install common-fate/granted/granted
# Configure SSO
granted sso populate
# Assume role
assume test-account
# Deploy to test
pnpm run test:deploy:all
# Switch to production
assume production-account
pnpm run production:deploy:all
Learn more: Setting up the AWS CLI with AWS SSO
Testing infrastructure
Manual testing
After applying changes, manually verify resources:
# Example: Verify Lambda function
aws lambda get-function --function-name my-function
# Example: Invoke Lambda
aws lambda invoke \
--function-name my-function \
--payload '{"key": "value"}' \
response.json
# Example: Check S3 bucket
aws s3 ls s3://my-bucket-name
# Example: Test IAM role
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/MyRole \
--role-session-name test
Unit tests with Jest
The starter kit includes Jest for testing constructs:
pnpm test # run all tests
pnpm run test:watch # watch mode for TDD
pnpm test -- --coverage # generate coverage report
Write tests in test/ directory. CDK provides snapshot testing for construct output validation.
Keep configuration in sync
Any time you edit .projenrc.ts, regenerate the project:
npx projen
Review the resulting git diff before committing. Generated files should never be hand-edited. Tweak .projenrc.ts, rerun Projen, and let the automation update tasks, workflows, and config.
Best practices
Before making changes
- Pull latest from main
- Review existing stack definitions
- Check for similar patterns in other stacks
- Plan resource naming conventions
During development
- Make small, incremental changes
- Run
pnpm run test:difffrequently - Format code regularly (
pnpm run biome -- --apply) - Add descriptive construct IDs
- Tag resources appropriately
Before committing
- Run full build:
pnpm run build - Review diff output carefully
- Check for sensitive data in code (no hardcoded secrets)
- Update tests if needed
- Write clear commit messages
After deploying
- Verify resources in AWS Console
- Test functionality manually
- Document any manual steps required
- Update stack outputs if needed
Next steps
- Understand the CI/CD Workflows for automated deployments
- Learn about Environment configuration
- Explore Branch-based Development for preview environments
- Review the Stacks reference for architecture patterns