cdk-diff-report
v1.1.1
Published
Run cdk diff, stream output, and post/update a formatted cost-aware summary comment on Bitbucket, GitHub, or GitLab PRs/MRs
Maintainers
Readme
cdk-diff-report
Run
cdk diffand get a beautifully formatted cost-aware summary posted to your Bitbucket, GitHub, or GitLab PR/MR — automatically.
What it does
- Runs
cdk diffand streams the raw output to your pipeline console - Parses the diff into a structured summary (added/modified/removed resources)
- Estimates monthly cost impact for each resource (live AWS Pricing API + static fallback)
- Posts a formatted Markdown comment to your PR/MR
- On subsequent runs, updates the same comment instead of creating duplicates
Quick Start — GitHub Action (recommended)
The fastest way to get started on GitHub:
# .github/workflows/cdk-diff.yml
name: CDK Diff
on: pull_request
jobs:
cdk-diff:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- run: npm ci # install your CDK app deps
- uses: dzon337/cdk-diff-visualizer@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-central-1That's it — every PR gets a cost-aware diff comment automatically.
Action Inputs
| Input | Description | Default |
|-------|-------------|---------|
| cdk-args | Arguments forwarded to cdk diff (comma-separated) | --all |
| html-output | Path to write an HTML report | — |
| dry-run | Preview markdown without posting | false |
| working-directory | Directory containing cdk.json | . |
| node-version | Node.js version to use | 20 |
Quick Start — npm CLI
1. Install
npm install -g cdk-diff-report2. Create a config file
Create a .cdkdiffreportrc file in the root of your CDK project (next to cdk.json):
{
"platform": "github",
"cdkArgs": ["--all"],
"htmlOutput": "cdk-diff.html"
}3. Run it
# In your CDK project directory (where cdk.json lives):
cdk-diff-report # run diff + post PR comment
cdk-diff-report --dry-run # run diff + print markdown preview (no posting)
cdk-diff-report --help # show all optionsConfiguration
Where to put .cdkdiffreportrc
Place the file in the root of the project where you run cdk diff — the same
directory as your cdk.json. The tool looks for .cdkdiffreportrc or
.cdkdiffreportrc.json in the current working directory.
my-cdk-project/
├── cdk.json
├── .cdkdiffreportrc ← put it here
├── lib/
│ └── my-stack.ts
├── bin/
│ └── app.ts
└── package.jsonAll options
{
// Required: which CI platform are you using?
// Options: "bitbucket" | "github" | "gitlab"
"platform": "github",
// Arguments forwarded to `cdk diff`
// Default: ["--all"]
// Examples:
// ["--all"] → diff all stacks
// ["MyStack"] → diff only MyStack
// ["--all", "--no-change-set"] → skip change set creation (faster)
"cdkArgs": ["--all"],
// Optional: write a standalone HTML report to this file path
// Great for CI artifacts — gives you a visual dashboard
"htmlOutput": "cdk-diff.html",
// Optional: never post to PR, just preview in the terminal
// Default: false
"dryRun": false,
// Bitbucket Server only — override the API base URL
// Default: "https://api.bitbucket.org/2.0"
"bitbucketApiUrl": "https://api.bitbucket.org/2.0",
// Self-managed GitLab only — override the API URL
// Default: auto-detected from $CI_API_V4_URL or "https://gitlab.com/api/v4"
"gitlabApiUrl": "https://gitlab.mycompany.com/api/v4"
}Note: JSON does not support comments. The
//comments above are for illustration only. Your actual.cdkdiffreportrcmust be valid JSON without comments.
Options reference
| Field | RC file key | Env var override | Default |
|-------|------------|------------------|---------|
| Platform | platform | CDK_DIFF_PLATFORM | "bitbucket" |
| CDK args | cdkArgs | CDK_DIFF_CDK_ARGS (comma-separated) | ["--all"] |
| HTML report | htmlOutput | CDK_DIFF_HTML_OUTPUT | — |
| Dry run | dryRun | CDK_DIFF_DRY_RUN (true/false) | false |
| BB API URL | bitbucketApiUrl | CDK_DIFF_BITBUCKET_API_URL | https://api.bitbucket.org/2.0 |
| GL API URL | gitlabApiUrl | CDK_DIFF_GITLAB_API_URL | auto-detected |
| BB workspace | workspace | CDK_DIFF_WORKSPACE | $BITBUCKET_WORKSPACE |
| BB repo slug | repoSlug | CDK_DIFF_REPO_SLUG | $BITBUCKET_REPO_SLUG |
Priority: CDK_DIFF_* env vars → .cdkdiffreportrc file → built-in defaults.
Multi-repo / Cross-repo setup
If your buildspec lives in a different repo than your CDK app, you have two options:
Option A: Use --cwd to point to the CDK project
# buildspec.yml (in your CI/CD repo)
phases:
build:
commands:
- git clone https://bitbucket.org/my-team/my-cdk-app.git /tmp/cdk-app
- cd /tmp/cdk-app && npm ci
- cdk-diff-report --cwd /tmp/cdk-appThe tool reads .cdkdiffreportrc and runs cdk diff from the --cwd directory.
Option B: Use environment variables (no config file needed)
Set everything via CDK_DIFF_* env vars in your buildspec — no need to put a
.cdkdiffreportrc in the CDK repo at all:
# buildspec.yml
env:
variables:
CDK_DIFF_PLATFORM: "bitbucket"
CDK_DIFF_CDK_ARGS: "--all"
CDK_DIFF_HTML_OUTPUT: "cdk-diff.html"
BITBUCKET_WORKSPACE: "my-team"
BITBUCKET_REPO_SLUG: "my-cdk-app"
secrets-manager:
BITBUCKET_ACCESS_TOKEN: "bitbucket/access-token"
phases:
build:
commands:
- export BITBUCKET_PR_ID=$(echo $CODEBUILD_WEBHOOK_TRIGGER | grep -oP '\d+')
- cd /path/to/cdk-app && npm ci
- cdk-diff-reportCost Estimation
The tool estimates the monthly cost impact of your infrastructure changes using a three-tier strategy:
- CloudFormation template analysis — reads actual resource properties from
cdk.out/(instance types, memory sizes, DB engines, etc.) - AWS Pricing API — queries real on-demand prices for EC2, RDS, ElastiCache, NAT Gateway, Lambda, and ECS Fargate
- Static fallback — uses a built-in table of ~80 resource types when the API is unavailable
The cost column appears in both the PR comment and the HTML report:
| ✅ Added | `MyBucket` | S3 › Bucket | +$0.023/mo |
| ✅ Added | `MyFunction` | Lambda › Func | +$0.620/mo |
| ❌ Removed | `OldDb` | RDS › DBInstance | -$49.64/mo |Cost estimates require AWS credentials (the same ones used for
cdk diff). If credentials are unavailable, the tool falls back to static estimates silently.
Platform Setup
GitHub Actions
Using the Marketplace Action (recommended)
# .github/workflows/cdk-diff.yml
name: CDK Diff
on: pull_request
jobs:
cdk-diff:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- run: npm ci
- uses: dzon337/cdk-diff-visualizer@v1
with:
cdk-args: '--all'
html-output: 'cdk-diff.html'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-central-1Using npx directly
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npx cdk-diff-report
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-central-1Environment variables (set automatically by GitHub Actions):
| Variable | Source |
|----------|--------|
| GITHUB_TOKEN | Auto-provided, needs pull-requests: write permission |
| GITHUB_REF | Auto-set, PR number extracted from refs/pull/N/merge |
| GITHUB_REPOSITORY | Auto-set (owner/repo) |
GitLab CI/CD
# .gitlab-ci.yml
cdk-diff:
image: node:20
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- npm ci
- npx cdk-diff-report
variables:
GITLAB_TOKEN: $CDK_DIFF_GITLAB_TOKENAdd CDK_DIFF_GITLAB_TOKEN in Settings → CI/CD → Variables (masked, protected).
Important:
CI_MERGE_REQUEST_IIDis only set in merge request pipelines. Make sure you userules: - if: $CI_PIPELINE_SOURCE == "merge_request_event".
| Variable | Source |
|----------|--------|
| GITLAB_TOKEN | You create this — project token with api scope |
| CI_PROJECT_ID | Auto-set |
| CI_MERGE_REQUEST_IID | Auto-set (MR pipelines only) |
| CI_API_V4_URL | Auto-set |
Bitbucket Pipelines
# bitbucket-pipelines.yml
pipelines:
pull-requests:
'**':
- step:
name: CDK Diff
script:
- npm ci
- npx cdk-diff-reportAdd BITBUCKET_ACCESS_TOKEN in Repository settings → Repository variables.
| Variable | Source |
|----------|--------|
| BITBUCKET_ACCESS_TOKEN | You create this — needs pullrequest:write scope |
| BITBUCKET_PR_ID | Auto-set |
| BITBUCKET_WORKSPACE | Auto-set |
| BITBUCKET_REPO_SLUG | Auto-set |
AWS CodePipeline + CodeBuild → Bitbucket
When your CDK project uses AWS CodePipeline triggered by Bitbucket PRs, CodeBuild doesn't set the Bitbucket env vars automatically. You need to provide them yourself.
Step 1: Store the Bitbucket token in Secrets Manager
aws secretsmanager create-secret \
--name bitbucket/access-token \
--secret-string "YOUR_BITBUCKET_APP_PASSWORD_OR_TOKEN"Create a Bitbucket App Password at https://bitbucket.org/account/settings/app-passwords/ with the
pullrequest:writescope. Or use a repository access token.
Step 2: Configure your buildspec
When CodeBuild is triggered by a PR webhook, the env var CODEBUILD_WEBHOOK_TRIGGER
is set to pr/123 (where 123 is the PR number). Extract it in your buildspec:
# buildspec.yml
version: 0.2
env:
secrets-manager:
BITBUCKET_ACCESS_TOKEN: "bitbucket/access-token"
variables:
# Set these to match your Bitbucket repository
BITBUCKET_WORKSPACE: "my-team"
BITBUCKET_REPO_SLUG: "my-cdk-app"
phases:
install:
runtime-versions:
nodejs: 20
commands:
- npm ci
- npm install -g aws-cdk cdk-diff-report
build:
commands:
# Extract PR ID from CodeBuild webhook trigger (format: "pr/123")
- export BITBUCKET_PR_ID=$(echo $CODEBUILD_WEBHOOK_TRIGGER | grep -oP '\d+')
- echo "PR ID = $BITBUCKET_PR_ID"
# Run the diff + post comment to Bitbucket
- cdk-diff-report
artifacts:
files:
- cdk-diff.html
discard-paths: yesStep 3: Set up CodeBuild
In your CodeBuild project:
- Source: Connect to Bitbucket via CodeStar Connections
- Webhook: Enable webhook events for
PULL_REQUEST_CREATEDandPULL_REQUEST_UPDATED - IAM Role: Grant the CodeBuild role permission to read from Secrets Manager:
{ "Effect": "Allow", "Action": "secretsmanager:GetSecretValue", "Resource": "arn:aws:secretsmanager:*:*:secret:bitbucket/access-token-*" } - Environment variables: Set
BITBUCKET_WORKSPACEandBITBUCKET_REPO_SLUGeither in the buildspec (above) or in the CodeBuild project configuration.
How it works
Bitbucket PR created/updated
→ CodeBuild webhook trigger: CODEBUILD_WEBHOOK_TRIGGER=pr/123
→ buildspec extracts PR ID: BITBUCKET_PR_ID=123
→ cdk-diff-report runs cdk diff
→ posts formatted comment to Bitbucket PR #123Tip: If you're using CodePipeline (not direct CodeBuild webhook), the PR ID is not available via
CODEBUILD_WEBHOOK_TRIGGER. In that case, pass it as a CodePipeline variable or use a Lambda step to resolve it from the source revision.
PR/MR Comment Preview
The tool posts a collapsible Markdown comment with per-stack breakdown:
## 🚀 CDK Diff Report
> 📈 **Estimated monthly cost impact: +$1.04/mo**
| ✅ Added | ⚠️ Modified | ❌ Removed | 🔐 IAM stacks | 💰 Est. cost |
|---------|------------|-----------|--------------|-------------|
| 5 | 0 | 0 | 1 | +$1.04/mo |
<details>
<summary><strong>MyStack</strong> — +5 · 🔐 IAM · 💰 +$1.04/mo</summary>
| Change | Logical ID | Type | Est. Cost |
|-----------|-------------|----------------|--------------|
| ✅ Added | `MyBucket` | S3 › Bucket | +$0.023/mo |
| ✅ Added | `MyFunction`| Lambda › Func | +$0.620/mo |
| ✅ Added | `MyQueue` | SQS › Queue | +$0.400/mo |
</details>On the next run, the same comment is updated with the latest diff.
Use as a Library
import { run, parseCdkDiff, generateMarkdownComment, enrichWithLivePricing } from 'cdk-diff-report';
// Full run (diff + comment)
await run({ dryRun: true });
// Just the parser
const diff = parseCdkDiff(rawCdkOutput);
console.log(diff.totalAdded, diff.costImpact.netCost);
// Platform-specific comment management
import { resolveGitHubEnv, upsertGitHubPrComment } from 'cdk-diff-report';
const env = resolveGitHubEnv();
await upsertGitHubPrComment(env, '## My Report\n...');FAQ
Q: Where does .cdkdiffreportrc go?
A: In the root of your CDK project — the same directory where cdk.json lives.
Q: Do I need AWS credentials for cost estimation?
A: The tool uses the same AWS credentials you already provide for cdk diff.
If credentials are missing, cost estimates fall back to static defaults.
Q: What if I don't have a PR (e.g. push to main)?
A: The tool runs cdk diff and prints the summary to the console, but skips
the PR comment gracefully — no crash.
Q: Can I diff only specific stacks?
A: Yes, set "cdkArgs": ["MyStack", "OtherStack"] in your config.
Q: Does it support monorepos?
A: Yes, run cdk-diff-report from the directory containing cdk.json.
Each CDK app needs its own .cdkdiffreportrc.
License
MIT
