When and why would you run Gradle with `--no-daemon`, and how does that differ from the default?
answer
- --no-daemon = one-shot JVM, exits after build
- daemon value = reuse; ephemeral CI has none
- saves memory + deterministic on shared runners
- cold JVM = always first-build-slow
- per-environment, not blanket rule
basics
~20 s--no-daemon runs the build in a fresh JVM that exits when the build finishes — no persistent process is reused or left behind. You use it in single-use environments like CI containers, where a warm daemon gives no benefit and just consumes memory.
solid answer
~50 sBy default Gradle delegates each build to a **persistent daemon**, so repeated builds reuse a warm JVM. `--no-daemon` (or `org.gradle.daemon=false`) instead runs the build in a **one-shot JVM that exits immediately afterward** — nothing is kept warm or left running. The daemon's whole value is *reuse*: JIT warmup and in-memory caches pay off across many builds. In an **ephemeral CI runner** that runs one build in a clean container and is then destroyed, there's no second build to benefit — the daemon would just hold extra memory for nothing, and an unexpectedly leftover daemon could even interfere on a shared host. So `--no-daemon` is the standard, deterministic choice there. The trade-off: a no-daemon build is always a **cold JVM**, so it's roughly as slow as the first daemon build and gets no warmup benefit. On developer machines, where you build repeatedly, you keep the daemon **on**. Modern CI with build caching and persistent runners sometimes keeps the daemon too — it's a per-environment decision, not a blanket rule.
code
bash · 5 lines# CI: clean, single-use build in a fresh JVM that exits afterward
./gradlew build --no-daemon
# Equivalent persistent setting (gradle.properties):
# org.gradle.daemon=falsego deeper
Know --no-daemon means a one-off build with no persistent JVM, and that CI often uses it.
Explain why ephemeral CI doesn't benefit from a daemon (no reuse) and the memory/determinism angle.
Weigh the trade-off per environment (ephemeral vs persistent runners) and note the always-cold cost.
Set org-wide policy: --no-daemon on ephemeral runners, daemon + caching on persistent runners, daemon on dev machines — and reason about runner cost, memory budgets, and build-time SLAs across the fleet.
## What `--no-daemon` actually changes Normally the client forwards your build to a **persistent daemon** that survives across invocations. With `--no-daemon`: - The build runs in a **single-use JVM** spun up for exactly this invocation. - That JVM **exits when the build completes** — no idle process lingers. - Nothing is reused from, or left for, other builds: no cross-build JIT warmth, no warm in-memory caches. Equivalent persistent settings: ```properties # gradle.properties org.gradle.daemon=false ``` ```bash # per-invocation ./gradlew build --no-daemon ``` ## Why disable it in CI The daemon optimizes the **repeated-build** case. A typical CI job is the opposite: - It runs in a **fresh container** that is **destroyed after the job**. - There is **no later build** in that container to reuse a warm daemon. In that setting a daemon brings no speedup (only the first cold build runs anyway) but adds downsides: - **Wasted memory** — an idle daemon holds heap for nothing. - **Non-determinism on shared/long-lived runners** — a daemon left from a previous job, possibly with different state or JVM args, can cause confusing reuse or contention. So `--no-daemon` gives a clean, predictable, single-use build. Historically Gradle even auto-disabled the daemon when it detected a CI environment, reinforcing this as the conventional choice. ## The cost of `--no-daemon` Because every no-daemon build is a **cold JVM**, you always pay full startup + JIT warmup. That's fine for a one-shot CI job, but on a dev machine it throws away the daemon's main benefit — there it would make every build feel as slow as a first build. ## It's a per-environment decision This isn't 'CI = no daemon' dogma: - **Ephemeral runner, one job per container** → `--no-daemon` is the clean default. - **Persistent/self-hosted runner reused across jobs** → keeping the daemon (plus build cache / configuration cache) can meaningfully speed up the pipeline, as long as you control daemon hygiene. - **Developer machine** → daemon **on**, always. ## Decision summary | Environment | Daemon? | Why | |---|---|---| | Dev laptop | On (default) | Repeated builds reuse warm JVM | | Ephemeral CI container (1 job, then destroyed) | `--no-daemon` | No reuse; saves memory; deterministic | | Persistent CI runner | Often on | Reuse across jobs can pay off if managed |
- Is the daemon always wrong for CI?No. On ephemeral one-job containers, --no-daemon is cleaner. But on persistent/self-hosted runners reused across jobs, keeping the daemon (with build and configuration caching) can speed up the pipeline — provided you manage daemon hygiene.
- How does --no-daemon performance compare to a warm daemon build?A no-daemon build is a cold JVM every time, so it's about as slow as a daemon's *first* build and never gets warmup benefit. A warm daemon build skips startup and runs JIT-optimized code, so it's faster on every repeat.
saying these in an interview costs you the question
- Asserting 'never use the daemon in CI' as an absolute — persistent runners can benefit.
- Recommending --no-daemon on developer machines, which throws away the daemon's core benefit.
- Thinking --no-daemon leaves a stopped daemon behind — it spawns a JVM that fully exits, nothing persists.