Projen

How Projen keeps the AWS CDK Starter Kit configuration-driven and reproducible.


Overview

Projen turns a single TypeScript definition into all repository configuration. Instead of maintaining dozens of JSON and YAML files by hand, you describe everything in .projenrc.ts and run npx projen to regenerate.

What is Projen?

Projen was created by former AWS CDK maintainers to bring CDK's infrastructure-as-code philosophy to project configuration. It ensures formatting, linting, workflows, and task automation stay consistent with the definition you check into source control.

Key principle: The .projenrc.ts file is the single source of truth. All generated files are outputs, not inputs.

Why the starter kit uses Projen

BenefitDescription
Environment-aware automationEach environment in .projenrc.ts produces matching npm scripts and GitHub Actions workflows with correct AWS accounts, regions, and branch settings
Governed defaultsEnforces shared settings (Biome formatting, Dependabot grouping, Node.js versions, gitignore patterns) so new projects start with recommended baselines
Self-healing configWhen dependencies or settings change, updating .projenrc.ts and rerunning Projen regenerates the repo to match
Reviewable changesConfiguration changes show up as diffs in pull requests

How it works

Configuration flow

The regeneration cycle

  1. Edit .projenrc.ts
  2. Run npx projen
  3. Review generated file changes
  4. Commit all changes together

Key sections in .projenrc.ts

Environment configuration

const environmentConfigs: (EnvironmentConfig & { name: Environment })[] = [
  { name: 'test', accountId: '987654321012', enableBranchDeploy: true },
  { name: 'production', accountId: '123456789012', enableBranchDeploy: false },
];

This array drives task and workflow generation. Each entry creates:

  • npm scripts for synth, diff, deploy, destroy
  • GitHub Actions workflows for deployment
  • Branch deployment tasks (if enabled)

Task generation

for (const config of environmentConfigs) {
  addCdkActionTask(project, {
    CDK_DEFAULT_ACCOUNT: config.accountId,
    CDK_DEFAULT_REGION: awsRegion,
    ENVIRONMENT: config.name,
    GITHUB_DEPLOY_ROLE: githubRole,
  });
}

Workflow generation

for (const config of environmentConfigs) {
  createCdkDeploymentWorkflows(
    project.github,
    config.accountId,
    awsRegion,
    config.name,
    githubRole,
    nodeVersion,
    config.enableBranchDeploy,
    orderedEnvironments,
  );
}

Files Projen manages

File/DirectoryPurpose
package.jsonDependencies, scripts, metadata
tsconfig.jsonTypeScript configuration
.github/workflows/CI/CD workflows
.gitignoreGit ignore patterns
biome.jsonCode formatting and linting
.projen/Projen internal files

Warning: Never edit generated files directly. Changes will be overwritten on the next npx projen run.

Common operations

Add a new environment

// In .projenrc.ts
{ name: 'staging', accountId: '111222333444', enableBranchDeploy: false },

Then regenerate:

npx projen

Change Node.js version

// In .projenrc.ts
const nodeVersion = '22';

Add a dependency

// In .projenrc.ts
project.addDeps('lodash');
project.addDevDeps('@types/lodash');

Modify npm scripts

Projen generates scripts via task definitions. To add custom tasks:

project.addTask('my-task', {
  exec: 'echo "Hello from custom task"',
});

Escape hatches

Sometimes you need to override generated content. Projen provides escape hatches:

// Override a specific file
project.tryFindObjectFile('package.json')?.addOverride('scripts.custom', 'my-command');

// Add content that won't be overwritten
project.gitignore.addPatterns('my-custom-file.txt');

Use escape hatches sparingly. If you find yourself using many overrides, consider whether Projen is the right fit for that configuration.

Learn more