Diff Mode (Baseline)
Track only new findings since your last accepted scan. Existing tech debt stays visible in summaries but never blocks a PR. The workflow that turns CDK Insights into a CI ratchet rather than an on-fire dashboard.
Why Diff Mode?
Adopt CDK Insights without Day-One churn
A real codebase typically has 100–500 findings on the very first scan. Without diff mode, every PR fails forever or you turn the tool off.
Catch regressions, not history
CI fails only when a PR adds a new finding. Pre-existing findings still show up in summaries (so they’re not invisible) but never block the build.
Move the bar deliberately
When a cleanup PR resolves findings, re-run --writeBaseline and commit the smaller baseline file. The acceptable level of debt ratchets down over time.
Stable across cosmetic changes
Findings are matched by a fingerprint (stack + construct path + rule), not by line number. Renaming a file or reformatting code does not produce false-new findings.
The Workflow
Snapshot today’s state once
On your main branch, with the current code, run the baseline command. It scans, computes a fingerprint per finding, and writes them to .cdk-insights-baseline.json.
npx cdk-insights scan --writeBaseline✅ Wrote baseline of 68 findings to .cdk-insights-baseline.jsonCommit the baseline file
The baseline is sorted and deterministic so it diffs cleanly in git. Treat it like any other source-controlled config — it’s the snapshot of what your team currently accepts.
git add .cdk-insights-baseline.json
git commit -m "chore: snapshot cdk-insights baseline"On every PR, run with --diff
The scan filters out anything already in the baseline before rendering and before fail-on-critical. Output shows the new finding count next to the existing-suppressed count.
npx cdk-insights scan --diff✅ No issues found across all stacks!
ℹ️ 📐 Diff result: 0 new findings (68 existing, suppressed).Fail builds only on new criticals
The exit code reflects only the new findings. Day-one debt no longer blocks the merge queue.
npx cdk-insights scan --diff --failOnCritical❌ Critical issues found. Exiting with code 1.
ℹ️ 📐 Diff result: 3 new findings (68 existing, suppressed).Move the bar after a cleanup
When a PR fixes existing findings (manually or via cdk-insights fix), re-run --writeBaseline so the new lower bar is what the next PR is measured against.
npx cdk-insights scan --writeBaseline✅ Wrote baseline of 61 findings to .cdk-insights-baseline.jsonCLI Flags
--writeBaselineRun the scan, collect every finding’s fingerprint, write .cdk-insights-baseline.json, and exit 0. Skips findings rendering — the operator wants a snapshot, not a report.
--diffFilter findings to only those new since the saved baseline. Both per-resource rendering and fail-on-critical evaluation operate on the filtered set.
--baseline <path>Override the baseline file path. Defaults to .cdk-insights-baseline.json in the current directory.
How fingerprints work
Each finding is identified by a stable composite key so the same issue produces the same id across runs:
<stackName>::<cdkPath>::<ruleId or issue:hash>stackNameDisambiguates resources with the same construct path that live in different stacks.
cdkPathThe CDK construct path (e.g. MyStack/Api/Bucket/Resource). Stable across re-synth — only changes when you rename a construct.
ruleIdExact rule identity when available (cdk-nag rules carry these). Distinguishes multiple findings on the same resource.
issueDigestFor findings without a rule ID, a short hash of the normalised issue text. Whitespace-insensitive and case-insensitive so trivial copy edits don’t churn fingerprints.
GitHub Actions Example
The recommended workflow: baseline lives in the repo, every PR scans with --diff, fails only on new criticals.
name: CDK Insights Diff
on:
pull_request:
branches: [main]
jobs:
diff:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- name: CDK Insights diff against main baseline
run: npx cdk-insights scan --all --diff --failOnCritical
env:
CDK_INSIGHTS_LICENSE_KEY: ${{ secrets.CDK_INSIGHTS_LICENSE_KEY }}Caveats
- Renaming a construct creates a new fingerprint. Because the cdkPath is part of the fingerprint, renaming
SecureBuckettoSecureDatalooks like a new finding. Re-run--writeBaselineafter significant refactors to absorb the rename. - Don’t run --writeBaseline on an unreviewed branch. The baseline is "what we accept." If a junior dev runs it on a branch with brand-new criticals, those criticals get baked into the accepted set. Restrict the command to maintainer-reviewed merges.
- Sensitive-data findings still fail by default. Hardcoded credentials are intentionally out of scope for the baseline — they’re always treated as new criticals unless you pass
--warnSensitive.
Pair with Auto-Fix
Diff mode tells you what’s new. The cdk-insights fix command can apply the mechanical remediation for many of those findings (enforceSSL, pointInTimeRecovery, Lambda runtime upgrades, KMS encryption, and more) so you spend reviewer time on the judgement calls, not the boilerplate.