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 npm 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
npm run build
# 4. Synthesize CloudFormation templates
npm run test:synth
# 5. Preview changes
npm run test:diff
# 6. Deploy changes (if diff looks good)
npm 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 npm commands
The starter kit provides convenient npm scripts for all operations. Run npx projen --help to see the full list of generated tasks.
Build and test
npm run build # compile, synth, test, lint in one go (used by CI)
npm test # jest with coverage enabled
Need a faster feedback loop? Use watch mode:
npm run watch # rebuild and re-test on file changes
npm run test:watch # jest watch mode with the repo's config
Code quality
npm run biome # check mode (validates formatting and linting)
npm run biome -- --apply # fix mode (note the extra --)
Example output:
$ npm 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
npm run test:synth # synthesize all stacks for the test account
npm run test:diff # diff all stacks against deployed state
npm run test:diff:stack StarterStack # diff a specific stack
npm run test:deploy:all # deploy all stacks
npm run test:deploy:stack FooStack # deploy a specific stack
npm run test:destroy:stack FooStack # destroy a specific stack
npm 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:
npm run test:branch:synth # synthesize with branch suffix
npm run test:branch:diff:stack Name # diff branch-specific stack
npm run test:branch:deploy:all # deploy all branch stacks
npm 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:
npm run test:branch:destroy:all
Working with CDK directly
While npm 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 npm 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
npm run biome
# Or fix issues automatically
npm 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:
npm 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
npm run test:deploy:all
export AWS_PROFILE=production-account
npm 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
npm run test:deploy:all
# Switch to production
assume production-account
npm 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:
npm test # run all tests
npm run test:watch # watch mode for TDD
npm 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
npm run test:difffrequently - Format code regularly (
npm run biome -- --apply) - Add descriptive construct IDs
- Tag resources appropriately
Before committing
- Run full build:
npm 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