skip to content

Your team is rolling out the configuration cache across a large multi-module build. Design a workflow using the problems report and the problems mode to migrate safely and prevent regressions.

level: seniorimportance: should knowfreq 28%

answer

  1. warn to baseline, capture count + categories
  2. fix shared convention plugins first (biggest leverage)
  3. marker as ticketed bridge for unowned tasks
  4. flip CI to fail when clean
  5. publish report as CI artifact, chart the count

basics

~20 s

Start in warn mode so builds keep working, use the HTML report to triage problems by category, fix or mark tasks incompatible, drive the count down, then flip CI to fail mode to lock in the clean state and catch any new regressions.

solid answer

~40 s

Phase 1 — **baseline**: enable the cache with `org.gradle.configuration-cache=true` and `problems=warn`, run representative tasks, and capture the report's total problem count as your baseline. Phase 2 — **triage**: group problems by category (untracked inputs, execution-time Project access, non-serializable state) and by owning module/plugin; fix the high-frequency, high-leverage categories first, often in shared convention plugins so one fix clears many. For tasks you don't own, use `notCompatibleWithConfigurationCache(reason)` with a tracking ticket as a bridge. Phase 3 — **enforce**: once the count hits zero (or only documented markers remain), set CI to `problems=fail` so any regression — a dependency bump, a new task — breaks the build immediately. Optionally cap `max-problems` low. Track the count over time and audit markers so the build stays clean as it evolves.

code

bash · 6 lines
bash
# CI: enforce clean state, fail on any problem, attach report
./gradlew build \
  -Dorg.gradle.configuration-cache=true \
  -Dorg.gradle.configuration-cache.problems=fail \
  -Dorg.gradle.configuration-cache.max-problems=0 \
  || (echo "see build/reports/configuration-cache/**/*.html"; exit 1)

go deeper

for a junior

Know the basic arc: warn first, read the report, fix, then fail to lock it in.

for a middle

Describe baseline-in-warn, triage by category, and enforce-in-fail, plus using the marker for unowned tasks.

for a senior

Emphasize leverage (shared convention plugins), per-environment policy, CI artifacts, and regression prevention.

for a principal

Frame it as org governance: metrics on problem counts, marker auditing, driving upstream plugin fixes, and policy for when a migration is 'done'.

## Goal Migrate a large build to the configuration cache without blocking developers, then keep it clean. The two levers are the **HTML problems report** (diagnosis) and the **problems mode** (`warn`/`fail`, the policy), plus the per-task **incompatibility marker** as a bridge. ## Phase 1 — baseline in warn mode Turn the cache on but stay non-blocking: ```toml org.gradle.configuration-cache=true org.gradle.configuration-cache.problems=warn ``` Run a representative set of tasks (build, test, assemble across modules). Open `configuration-cache-report.html` and record the **total problem count** and the **category breakdown**. This is your migration backlog and a metric you can chart. ## Phase 2 — triage and fix by leverage The report groups problems by category and exposes the ownership tree (build → task → input → call site). Prioritize: 1. **High-frequency categories** — e.g. dozens of untracked `System.getProperty` reads → switch to `providers.systemProperty(...)`. 2. **Shared convention plugins** — fixing one `build-logic` plugin often clears the same problem across every module that applies it. This is the biggest lever in a multi-module build. 3. **Execution-time model access** — capture values into `Provider`/`Property` at configuration time or inject services. For tasks you **don't own** (third-party/core) and can't migrate now, apply `notCompatibleWithConfigurationCache("reason; TICKET-123")` as a documented bridge so the rest of the build can move forward. Avoid using markers on code you own. ## Phase 3 — enforce and prevent regression When the report reaches zero (or only documented, ticketed markers remain), flip CI to fail-fast: ```toml org.gradle.configuration-cache.problems=fail org.gradle.configuration-cache.max-problems=0 ``` Now a new problem — someone adds a task that reads env vars at config time, or a plugin upgrade reintroduces a bad pattern — fails CI immediately with the report attached. Optionally keep developers on `warn` locally for a smoother inner loop while CI enforces `fail`. ## Ongoing hygiene - **Publish the report as a CI artifact** so failures are diagnosable without re-running. - **Chart the problem count** over the migration so progress is visible. - **Audit incompatibility markers** periodically and drive owners (including upstream plugin authors) to remove the need for them. The net effect: warn unblocks the migration, the report drives the work by leverage, and fail-in-CI makes the clean state durable.

  • Why fix shared convention plugins before individual modules?
    In a multi-module build a single bad pattern in a build-logic convention plugin reproduces across every module that applies it. Fixing the plugin once clears the same problem everywhere — far higher leverage than per-module fixes.
  • How do you stop a clean build from silently regressing later?
    Set CI to problems=fail (optionally max-problems=0) so any newly introduced problem breaks the build immediately, publish the report as a CI artifact, and audit incompatibility markers so they don't accumulate.
  • Should developers run fail mode locally during the migration?
    Usually not mid-migration — warn keeps their inner loop unblocked while they fix problems. CI carries the fail enforcement. After the migration completes, aligning local and CI on fail prevents drift.

saying these in an interview costs you the question

  • Flipping straight to fail before the build is clean, blocking the whole team.
  • Mass-marking owned tasks incompatible instead of fixing them.
  • Fixing per-module without touching the shared plugin that re-creates the problem everywhere.
  • Not preserving/publishing the report, so CI failures aren't diagnosable.

context