Skip to main content
Skip to main content

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

1

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.json
2

Commit 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"
3

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).
4

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).
5

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.json

CLI Flags

--writeBaseline

Run 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.

--diff

Filter 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>
stackName

Disambiguates resources with the same construct path that live in different stacks.

cdkPath

The CDK construct path (e.g. MyStack/Api/Bucket/Resource). Stable across re-synth — only changes when you rename a construct.

ruleId

Exact rule identity when available (cdk-nag rules carry these). Distinguishes multiple findings on the same resource.

issueDigest

For 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 SecureBucket to SecureData looks like a new finding. Re-run --writeBaseline after 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.

Read the Auto-Fix docs