How does Gradle continuous build compare with external file watchers or CI re-triggering for a team's fast-feedback loop, and when would you choose each?
answer
- -t = native inner loop, warm daemon+VFS+cache
- external watcher = arbitrary paths/commands, live-reload
- CI = shared reproducible gatekeeping
- layers, not competitors
- remote cache speeds CI
basics
~20 sContinuous build is built into Gradle and reuses the warm daemon, VFS, and build cache for cheap re-runs locally. External watchers (entr, IDE, nodemon-style) or CI re-triggers are more flexible but pay full startup each time. Use -t for the local inner loop; use CI for shared verification.
solid answer
~50 sContinuous build (`-t`) is the **native inner-loop** option: it reuses the **persistent daemon** (no JVM warm-up per change), the **warm VFS** (no full re-hash), and the **build cache**, so re-runs are cheap and changes are detected via OS-level watching scoped to declared inputs. **External watchers** (e.g. `entr`, IDE run-on-save, custom scripts) can watch arbitrary paths and run arbitrary commands — useful when you need to react to files Gradle doesn't model as inputs, or coordinate multiple tools — but each invocation typically starts a fresh Gradle command (still daemon-backed, but with full configuration each time and weaker input-scoping). **CI re-triggering** is for **shared, reproducible verification** on push/PR, not interactive speed. Choose continuous build for tight local loops on declared-input tasks; an external watcher when you need behavior outside Gradle's input model or multi-tool orchestration; and CI for gatekeeping correctness across the team. They are complementary layers, not competitors.
code
bash · 5 lines# Native inner loop
gradle -t test
# External watcher when you need non-input paths or multi-tool chaining
ls **/*.kt | entr -c gradle testgo deeper
Know continuous build is the built-in local loop and CI runs builds for the whole team.
Contrast warm-daemon re-runs vs. fresh external invocations and name when an external watcher is needed (live-reload, non-input files).
Frame the three as complementary layers and justify the choice per scenario, including remote-cache use in CI.
Define org-wide inner-loop and CI strategy: standard tooling, cache topology (local + remote), and where continuous build vs. dev-servers belong.
## Three layers of feedback ### 1. Gradle continuous build (`-t`) — native inner loop Strengths: - **Warm daemon**: no per-change JVM/Gradle startup. - **Warm VFS + FS watching**: change detection is incremental and scoped to **declared inputs**. - **Build cache + incrementality**: each re-run does minimal work. - Zero extra tooling; one flag. Limits: only watches declared inputs; struggles with blocking tasks and build-script edits (see limits topic). ### 2. External file watchers — flexible orchestration Tools like `entr`, `watchexec`, IDE 'run on save', or framework dev-servers watch **arbitrary paths** and run **any command**. Use them when: - You must react to files Gradle doesn't model as task inputs. - You need to chain non-Gradle steps (regenerate, then notify, then reload a browser). - You want app **live-reload**, which continuous build alone doesn't provide. Cost: each trigger usually launches a fresh `gradle` invocation — still daemon-backed, but it re-runs **configuration** every time and lacks continuous build's input-scoped watching, so it can be noisier or redundant. ```bash # external watcher example (entr): re-run tests when any .kt changes ls **/*.kt | entr -c gradle test ``` ### 3. CI re-triggering — shared verification CI runs the build on push/PR for **reproducibility and gatekeeping**, not interactive latency. It is the source of truth for 'does it build/pass for everyone', often with a **remote build cache** to stay fast. It complements, never replaces, the local loop. ## Decision guide | Need | Pick | |------|------| | Fast local loop on compile/test/codegen with declared inputs | **continuous build (`-t`)** | | React to non-input files / chain multiple tools / app live-reload | **external watcher / dev-server** | | Shared, reproducible pass/fail across the team | **CI** (with remote cache) | ## The senior insight These are **layers**: `-t` for the personal inner loop, external watchers when you outgrow Gradle's input model, CI for collective correctness. The performance edge of continuous build comes specifically from reusing the **daemon + VFS + cache**; an external watcher that spawns cold-ish invocations trades that efficiency for flexibility.
- Why can continuous build be faster than an external watcher running `gradle test` on each save?Continuous build keeps one daemon and a warm VFS and re-triggers only on declared-input changes, reusing configuration and the build cache. An external watcher typically launches a fresh gradle invocation that re-runs configuration each time and isn't input-scoped, so it does more redundant work.
- Where does a remote build cache fit into this picture?It mainly accelerates CI and cross-machine builds by sharing task outputs; locally, continuous build already benefits from the local cache, and a remote cache can seed cold machines.
Continuous build is the built-in cruise control of your own car (efficient, integrated); an external watcher is a custom rig you bolt on for tasks the car doesn't handle; CI is the official inspection station that signs off for everyone.
saying these in an interview costs you the question
- Treating CI re-triggering as a substitute for a local inner loop (it's for shared verification, not latency).
- Claiming external watchers are always faster — they usually pay full configuration per run.
- Ignoring that continuous build's speed depends on the daemon/VFS/cache being warm.