cdk-diff-report
v1.1.3
Published
Automated AWS CDK infrastructure diff with cost estimation for pull requests. Posts formatted, cost-aware summary comments to GitHub, GitLab, and Bitbucket PRs/MRs. Available as a GitHub Action, npm CLI, or Node.js library.
Maintainers
Readme
cdk-diff-report
Automated AWS CDK infrastructure diff with cost estimation for pull requests.
Run cdk diff in CI/CD and automatically post a formatted, cost-aware summary comment to your GitHub, GitLab, or Bitbucket pull request. Shows exactly which AWS resources are being added, modified, or removed — and how much it'll cost.
Why use this
- See infrastructure changes before merging — every PR gets a clear breakdown of added, modified, and removed AWS resources
- Know the cost before you deploy — real-time cost estimates from the AWS Pricing API, covering EC2, RDS, Lambda, ECS Fargate, ElastiCache, NAT Gateway, and 80+ other resource types
- Works everywhere — GitHub Actions, GitLab CI/CD, Bitbucket Pipelines, AWS CodeBuild
- Zero config for GitHub — just add the action and you're done
- Idempotent comments — updates the same PR comment on each push instead of spamming new ones
- HTML report — optionally generate a standalone HTML dashboard as a CI artifact
How it works
- Runs
cdk diffand streams the raw output to your pipeline console - Parses the diff into structured resource changes (added, modified, removed)
- Reads your CloudFormation templates from
cdk.out/to extract actual resource properties - Queries the AWS Pricing API for real on-demand prices (falls back to a built-in static cost table)
- Posts a formatted Markdown comment to your PR/MR
- On subsequent pushes, updates the same comment instead of creating duplicates
Quick start
GitHub Action (recommended)
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
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 |
npm CLI
npm install -g cdk-diff-reportCreate .cdkdiffreportrc in your CDK project root (next to cdk.json):
{
"platform": "github",
"cdkArgs": ["--all"],
"htmlOutput": "cdk-diff.html"
}Run it:
cdk-diff-report # run diff and post to your PR
cdk-diff-report --dry-run # preview the markdown without posting
cdk-diff-report --cwd /path # run from a different directory
cdk-diff-report --help # show all optionsnpx (no install)
npx cdk-diff-report --dry-runConfiguration
Config file
Place .cdkdiffreportrc (or .cdkdiffreportrc.json) next to your cdk.json:
my-cdk-project/
├── cdk.json
├── .cdkdiffreportrc
├── lib/
│ └── my-stack.ts
├── bin/
│ └── app.ts
└── package.jsonFull example:
{
"platform": "github",
"cdkArgs": ["--all"],
"htmlOutput": "cdk-diff.html",
"dryRun": false,
"bitbucketApiUrl": "https://api.bitbucket.org/2.0",
"gitlabApiUrl": "https://gitlab.mycompany.com/api/v4"
}Environment variables
Every option can be set via environment variables — useful in CI/CD when you don't want a config file.
| Option | Config key | Environment variable | 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 | false |
| Bitbucket API URL | bitbucketApiUrl | CDK_DIFF_BITBUCKET_API_URL | https://api.bitbucket.org/2.0 |
| GitLab API URL | gitlabApiUrl | CDK_DIFF_GITLAB_API_URL | auto-detected |
| Bitbucket workspace | workspace | CDK_DIFF_WORKSPACE | $BITBUCKET_WORKSPACE |
| Bitbucket repo slug | repoSlug | CDK_DIFF_REPO_SLUG | $BITBUCKET_REPO_SLUG |
Priority: environment variables → config file → built-in defaults.
Cross-repo setups
If your CI/CD config lives in a different repo than your CDK app:
Use --cwd to point to the CDK project:
- 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-appOr use environment variables (no config file needed):
env:
variables:
CDK_DIFF_PLATFORM: "bitbucket"
CDK_DIFF_CDK_ARGS: "--all"Cost estimation
The tool estimates monthly cost impact using a three-tier approach:
- Template analysis — reads resource properties from
cdk.out/(instance types, memory sizes, DB engines, etc.) - AWS Pricing API — fetches real on-demand prices for EC2, RDS, ElastiCache, NAT Gateway, Lambda, and ECS Fargate
- Static fallback — built-in cost table covering ~80 AWS resource types when the API is unavailable
Supported resource types
EC2 instances, RDS databases, Aurora clusters, ElastiCache clusters, NAT Gateways, Lambda functions, ECS Fargate services, EKS clusters, S3 buckets, DynamoDB tables, ALB/NLB load balancers, CloudFront distributions, API Gateway (REST & HTTP), SQS queues, SNS topics, EventBridge rules, Step Functions, Kinesis streams, Route 53 hosted zones, EFS file systems, KMS keys, Secrets Manager, WAFv2, CodeBuild, CodePipeline, CloudWatch alarms and dashboards, Cognito user pools, AppSync APIs, and more.
Example output
| ✅ Added | MyBucket | S3 › Bucket | +$0.023/mo |
| ✅ Added | MyFunction | Lambda › Func | +$0.620/mo |
| ❌ Removed | OldDb | RDS › DBInstance | -$49.64/mo |Cost estimates use the same AWS credentials you provide for cdk diff. If credentials are unavailable, the tool falls back to static estimates silently.
Platform setup
GitHub Actions
Using the Marketplace Action:
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-1| Variable | How it's set |
|----------|-------------|
| GITHUB_TOKEN | Auto-provided; needs pull-requests: write permission |
| GITHUB_REF | Auto-set; PR number is extracted from refs/pull/N/merge |
| GITHUB_REPOSITORY | Auto-set (owner/repo) |
GitLab CI/CD
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).
Make sure you use merge_request_event as the pipeline source — CI_MERGE_REQUEST_IID is only available in merge request pipelines.
| Variable | How it's set |
|----------|-------------|
| 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
pipelines:
pull-requests:
'**':
- step:
name: CDK Diff
script:
- npm ci
- npx cdk-diff-reportAdd BITBUCKET_ACCESS_TOKEN in Repository settings → Repository variables.
| Variable | How it's set |
|----------|-------------|
| 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 using AWS CodePipeline triggered by Bitbucket PRs, CodeBuild doesn't set the Bitbucket env vars automatically. Here's how to wire it up:
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 with the pullrequest:write scope.
2. Configure your buildspec:
version: 0.2
env:
secrets-manager:
BITBUCKET_ACCESS_TOKEN: "bitbucket/access-token"
variables:
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:
- export BITBUCKET_PR_ID=$(echo $CODEBUILD_WEBHOOK_TRIGGER | grep -oP '\d+')
- cdk-diff-report
artifacts:
files:
- cdk-diff.html
discard-paths: yes3. Set up CodeBuild:
- Source: Connect to Bitbucket via CodeStar Connections
- Webhook: Enable
PULL_REQUEST_CREATEDandPULL_REQUEST_UPDATEDevents - IAM Role: Grant permission to read from Secrets Manager:
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:*:*:secret:bitbucket/access-token-*"
}How the flow works:
Bitbucket PR → CodeBuild webhook (CODEBUILD_WEBHOOK_TRIGGER=pr/123)
→ buildspec extracts PR ID → cdk-diff-report runs
→ posts comment to Bitbucket PR #123What the PR comment looks like
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 push, the same comment is updated with the latest diff.
Use as a library
Import individual functions into your own Node.js scripts:
import { run, parseCdkDiff, generateMarkdownComment, enrichWithLivePricing } from 'cdk-diff-report';
// Full pipeline: run diff, enrich with pricing, post comment
await run({ dryRun: true });
// Just parse cdk diff output
const diff = parseCdkDiff(rawCdkOutput);
console.log(diff.totalAdded, diff.costImpact.netCost);
// Post to GitHub directly
import { resolveGitHubEnv, upsertGitHubPrComment } from 'cdk-diff-report';
const env = resolveGitHubEnv();
await upsertGitHubPrComment(env, '## My Report\n...');Exported API
| Export | Description |
|--------|------------|
| run(options) | Full pipeline: diff → parse → price → comment |
| parseCdkDiff(raw) | Parse raw cdk diff output into structured data |
| generateMarkdownComment(diff) | Generate a Markdown PR comment from parsed diff |
| generateHtml(diff) | Generate a standalone HTML report |
| enrichWithLivePricing(resources, cwd) | Enrich resources with live AWS pricing |
| estimateResourceCost(awsType) | Get static cost estimate for an AWS resource type |
| calculateCostImpact(resources) | Calculate total cost impact from resource changes |
| resolveGitHubEnv() | Resolve GitHub environment variables |
| upsertGitHubPrComment(env, md) | Create or update a GitHub PR comment |
| resolveGitLabEnv() | Resolve GitLab environment variables |
| upsertMrNote(env, md) | Create or update a GitLab MR note |
| resolveBitbucketEnv() | Resolve Bitbucket environment variables |
| upsertPrComment(env, md) | Create or update a Bitbucket PR comment |
Common use cases
- AWS CDK pull request reviews — see infrastructure changes before merging
- Infrastructure cost tracking — catch unexpected cost increases early in the review process
- IAM change visibility — security-sensitive changes are flagged automatically
- Compliance and audit — generate HTML reports as CI artifacts for audit trails
- Monorepo support — run per CDK app with separate configs
- Multi-platform teams — same tool works across GitHub, GitLab, and Bitbucket
FAQ
Where does .cdkdiffreportrc go?
In the root of your CDK project — the same directory where cdk.json lives.
Do I need AWS credentials for cost estimation?
The tool uses the same credentials you already provide for cdk diff. If they're missing, costs fall back to static defaults.
What if there's no PR (e.g. push to main)?
The tool runs cdk diff and prints the summary to the console. It skips the PR comment gracefully — no crash.
Can I diff only specific stacks?
Yes. Set "cdkArgs": ["MyStack", "OtherStack"] in your config.
Does it support monorepos?
Yes. Run cdk-diff-report from the directory containing cdk.json. Each CDK app needs its own .cdkdiffreportrc.
What Node.js versions are supported? Node.js 18 and above.
Is it free? Yes, fully open source under the MIT license.
Related tools and alternatives
If you're looking for AWS CDK diff and cost estimation tools, cdk-diff-report is a lightweight alternative to larger platforms like Infracost, Terraform Cloud, or Pulumi's built-in diff. It's purpose-built for AWS CDK projects and works as a drop-in GitHub Action, GitLab CI job, or Bitbucket Pipeline step.
License
MIT
