Watch Mode
Live feedback for CDK static analysis. Re-runs `cdk synth` plus the rule pack on every save and reprints the findings table โ synth only, never deploys. Reuses the same `watch` block in cdk.json that `cdk watch` reads, so a single config drives both tools.
Why Watch Mode?
Tight feedback while editing infrastructure
See findings on save, not after a CI run. The same dev-loop you expect from prettier/eslint/biome, but for CloudFormation-level checks across IAM, S3, KMS, Lambda, and 30+ other AWS services.
Doesn't deploy โ unlike `cdk watch`
`cdk watch` is a shortcut for `deploy --watch` and pushes real infra to AWS on every save. `cdk-insights scan --watch` shells out to `cdk synth` only and runs the static rule pack against the templates. Zero AWS API calls beyond what `cdk synth` already does.
Reuses your existing cdk.json watch config
If you've already configured `watch.include` / `watch.exclude` for `cdk watch`, the same block drives the cdk-insights loop โ one configuration, two tools.
AI off by default โ credits stay safe
AI analysis is forced off in watch mode so a fresh cache miss on every keystroke doesnโt silently drain your monthly credits. Run `cdk-insights scan` manually when you want AI on a known-good intermediate state.
How it works
Start the watch loop
Run from your CDK app root. The first iteration does the full auth, license, and synth pipeline. Subsequent runs reuse the resolved license context โ the loop never re-authenticates.
# direct invocation:
npx cdk-insights scan --watch
# or, after `npx cdk-insights init` (1.29.0+):
npm run cdk-insights:watch๐ CDK Insights (free tier)
โน๏ธ ๐ Watch mode โ watching 1 include pattern(s)
AI analysis disabled in watch mode. Press Ctrl+C to exit.
โน๏ธ ๐ Initial scanEdit a file in your CDK app
Save any file inside your watch globs. The loop debounces for 300 ms (so a burst of saves triggers one re-run, not five), then re-runs `cdk synth` and re-evaluates the rule pack. The terminal clears between runs so the latest result is in focus.
// edit lib/api-stack.ts
const api = new apigateway.RestApi(this, "Api");๐ change lib/api-stack.ts
โน๏ธ โก Synthesizing all CDK stacks...
โ
Synthesis complete. Found 1 stack to analyze.
โ Done at 14:22:08Synth failures preserve last good results
If `cdk synth` fails (TypeScript compile error, missing context lookup), the watcher reports the error and keeps the last good results visible. Fix and save โ the loop picks up where it left off.
// introduce a TS error
const x: number = "not a number";๐ change lib/api-stack.ts
โ Synth failed โ keeping last good results. Fix the error and save again.Stop with Ctrl+C
SIGINT (and SIGTERM) cleanly close the chokidar watcher before exiting. Nothing is left running.
^Cโน๏ธ ๐ Stopping watcher.Reuses your cdk.json watch block
The watcher reads the same `watch.include` / `watch.exclude` block CDK uses for `cdk watch`. One config, two tools.
{
"app": "node bin/my-app.js",
"watch": {
"include": ["lib/**/*.ts", "bin/**/*.ts"],
"exclude": ["**/*.test.ts", "**/handlers/**"]
}
}include (default)When `watch.include` is unset, defaults to the project root โ i.e. watch everything. Matches `cdk watch` exactly so a single config drives both tools.
exclude (mandatory)Always appended to user-provided excludes (never replaces them): `**/.*`, `**/.*/**`, `**/node_modules/**`, plus the cloud-assembly output dir (`output` in cdk.json, default `cdk.out`). The output dir is excluded only when it resolves under the project root as a relative path.
exclude (user-provided)Use this to narrow scope for a static-analysis loop โ e.g. `**/*.test.ts`, `**/handlers/**` to skip Lambda runtime code that does not affect synth output.
Watch-safe defaults
A few flags are forced or rejected because they donโt make sense in a re-rendering live loop. The watcher chooses these regardless of what you pass on the command line:
AI analysisโForced off (`--local`)Cache-miss = 1 credit per resource. Running on every save would burn credits with each edit. Run `cdk-insights scan` manually for AI feedback on a known-good intermediate state.
--writeBaselineโRejected with errorWould silently overwrite the baseline file on every save, baking in whatever findings happen to exist mid-edit.
--diffโRejected with errorFilters findings against a moving target; meaningless when re-running continuously.
--github / --withIssue / --prCommentโForced offWould otherwise create a GitHub issue or post a PR comment on every save.
failOnCriticalโForced offWould kill the watcher on the first critical finding.
--output json / sarif / markdown / github-actionsโCoerced to `table` (one-line warning)Machine formats don't make sense for a re-rendering live loop.
Caveats
- Synth is whole-app, not per-file. CDKโs synth output is a global function of the construct tree โ thereโs no per-file CFN generation. The watch loop runs the full synth on every save. On small apps thatโs typically 1โ3 seconds; on large multi-stack apps it can be 5+. Match your
cdk.jsonappcommand to the fastest TS runner you can (e.g.tsxor precompiled JS) to keep the loop snappy. - Default include is the whole project root. Matches
cdk watchbehaviour: every file change triggers a re-synth, including handler code that doesnโt affect CFN output. Add anexcludeblock in cdk.json to narrow scope (e.g.**/handlers/**,**/*.test.ts) โ the same config benefitscdk watchtoo. - AI is intentionally off. For AI-powered analysis, run
cdk-insights scanmanually on a known-good intermediate state. Watch mode is the fast static-analysis loop; AI is the deeper one-shot tool.
Pair with Diff Mode
Watch mode is for the dev loop; diff mode is for the CI gate. Use them together: watch while youโre editing, then a one-shot --diff scan in CI fails only when a PR introduces a new finding.