Local Development

Daily commands for building, testing, formatting, and deploying CDK infrastructure from your workstation.


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 test with 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:diff frequently
  • 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