When would you reach for evaluationDependsOn(':lib') versus evaluationDependsOnChildren(), and what are the risks?
answer
- evaluationDependsOn = one target
- evaluationDependsOnChildren = parent forces children
- config order only, not tasks
- smell for eager reads
- cycle + slow-config risk
basics
~10 sUse evaluationDependsOn(':lib') in one project to force a specific other project to be configured first; use evaluationDependsOnChildren() in a parent to configure all its children first. Both can mask design issues and slow configuration.
solid answer
~50 sBoth force **configuration-phase** ordering. `evaluationDependsOn(":lib")` (called in project A) guarantees `:lib` is fully evaluated before A finishes evaluating — useful when A must read `:lib`'s *configured model* (an extension value populated by `:lib`'s plugin, say) at configuration time. `evaluationDependsOnChildren()` is the parent-side variant: a parent calls it to ensure every child project is configured before the parent's own script proceeds. Risks: (1) it forces those projects to configure even when not otherwise needed, hurting configuration time and breaking with isolated-projects optimizations; (2) it can create configuration-ordering cycles (`A` depends on `B`, `B` depends on `A`) which fail the build; (3) it's usually a symptom that you're reading state eagerly when a lazy `Provider` would remove the dependency. So prefer providers; reach for these only when you genuinely need another project's *configured* state during your own configuration.
code
kotlin · 7 lines// parent build.gradle.kts — aggregate children's configured model
evaluationDependsOnChildren()
val childOutputs = childProjects.values.map { child ->
child.extensions.getByType(ReportExtension::class.java).reportFile
}
// childOutputs is now safe to read because all children were evaluated firstgo deeper
Just know these APIs force one project to be configured before another; details optional.
Distinguish the two APIs and state that they affect configuration, not execution.
Explain when each is legitimate, the cycle/slow-config risks, and why providers are usually better.
Govern usage: flag new evaluationDependsOn in review, push provider-based wiring and isolated-projects compatibility.
## The two APIs ```kotlin // In :app — force a specific dependency evaluationDependsOn(":lib") // In a parent project — force ALL children first evaluationDependsOnChildren() ``` Both affect **evaluation (configuration) order only**. Neither implies a compile dependency and neither sets task execution order. ## When each fits - `evaluationDependsOn(":path")` — you need exactly one other project's configured state. Example: `:app` reads a value that `:lib`'s applied plugin writes into `:lib`'s extension, and you must read it while configuring `:app`. - `evaluationDependsOnChildren()` — a *parent* aggregates or inspects its children's configured model. Common in older 'umbrella' builds where a root or grouping project iterated child outputs at configuration time. ## Why it's a code smell These APIs exist for the rare legitimate case, but their frequent appearance usually means you're **reading state eagerly**. Most of the time the value you want is an *output* or a *property*, which a `Provider` can carry lazily — no ordering needed. Eagerly forcing configuration also: - **Slows builds**: forced projects configure even when their tasks aren't requested. - **Fights isolated projects**: Gradle's isolated-projects feature parallelizes/isolates per-project configuration; cross-project configuration coupling undermines it. - **Risks cycles**: if A forces B and B forces A, configuration cannot be ordered and the build fails. ## Decision flow 1. Can I model the needed value as a `Provider`/task output and wire it lazily? -> Do that. No ordering API needed. 2. Do I truly need another project's *configured model* (not just an output) at my configuration time? -> Use `evaluationDependsOn` for a single target, `evaluationDependsOnChildren` for the parent-of-children shape. 3. Watch for cycles and the configuration-time cost. ## Note vs task ordering Don't confuse with task ordering: `dependsOn` (hard), `mustRunAfter`/`shouldRunAfter` (relative). Those run in the execution phase; `evaluationDependsOn*` run in configuration.
- What happens if evaluationDependsOn forms a cycle?Gradle cannot determine a valid configuration order and fails the build with a circular evaluation dependency error.
- Does evaluationDependsOn add a project compile dependency?No. It only sequences configuration. Compile/runtime dependencies are declared separately in the dependencies block (e.g. implementation(project(':lib'))).
saying these in an interview costs you the question
- Using evaluationDependsOnChildren as the default way to wire outputs (should be providers).
- Confusing it with dependsOn task ordering.
- Ignoring the configuration-time cost and cycle risk.