What does `isTransitive = false` do on a dependency, and how does it differ from excludes?
answer
- isTransitive = false -> only the artifact
- exclude -> named coordinates only
- fat/uber jars, over-declared metadata
- you own missing classes -> NoClassDefFound
- Groovy: transitive = false
basics
~10 sSetting isTransitive = false makes Gradle bring in only that one artifact and none of its declared dependencies. Excludes prune specific coordinates; isTransitive = false drops the entire transitive subtree at once.
solid answer
~40 s`exclude` removes named coordinates from a dependency's subgraph; `isTransitive = false` takes the all-or-nothing route — Gradle resolves just the artifact you named and ignores everything in its metadata. You write `implementation("com.acme:foo:1.0") { isTransitive = false }`. It's useful for fat/uber jars that already bundle their dependencies, or when you deliberately want to supply each transitive yourself for tight control. The danger is that you now own the full responsibility of providing any classes `foo` actually needs at runtime; miss one and you get `NoClassDefFoundError`. So reach for it sparingly — usually when a dependency's published metadata over-declares, or the jar is self-contained. For removing just a couple of unwanted artifacts, targeted `exclude` is safer because it keeps the rest of the transitive graph intact.
code
kotlin · 6 linesdependencies {
// self-contained shaded jar: skip its declared deps entirely
implementation("com.acme:foo-all:1.0") {
isTransitive = false
}
}go deeper
Know that it disables pulling the dependency's own dependencies; only the named jar arrives.
Contrast with exclude (named coordinates vs whole subtree) and name the runtime NoClassDefFound risk.
Justify it for shaded/self-contained jars or over-declared metadata and weigh it against constraints for conflicts.
Discourage configuration-wide non-transitivity; treat per-dependency isTransitive=false as an audited exception with documented justification.
## Two different scalpels Both `exclude` and `isTransitive = false` shrink the graph, but at different granularity: - **exclude(group/module):** surgically remove *named* coordinates; everything else `foo` declares still comes in. - **isTransitive = false:** drop the *entire* transitive subtree; only the single requested artifact (`foo` itself) is resolved. ## Syntax ```kotlin dependencies { implementation("com.acme:foo:1.0") { isTransitive = false } } ``` In Groovy DSL it's `transitive = false`. There's also a configuration-level switch, `configurations.named("x") { isTransitive = false }`, which makes *all* dependencies in that configuration non-transitive — rare and aggressive. ## When it's the right tool - **Self-contained / shaded jars:** the artifact already embeds its dependencies, so pulling the declared ones would duplicate classes. - **Over-declared metadata:** a poorly published library lists deps you don't need; you'd rather hand-pick. - **Strict control:** you want to declare every transitive explicitly for reproducibility/audit. ## The risk You inherit responsibility for every class `foo` needs. Because Gradle no longer pulls them, missing pieces don't fail the build — they fail at runtime with `NoClassDefFoundError`/`ClassNotFoundException`. That's a worse failure mode than a resolution error, so use it only when you're confident the artifact is self-sufficient or you're adding the needed deps yourself. ## Decision rule - Need to remove one or two specific artifacts? -> `exclude`. - The whole subtree is unwanted or already bundled? -> `isTransitive = false`. - Need to *replace* a version that conflicts? -> neither; use a constraint/strict version.
- What failure mode does isTransitive = false risk, and why doesn't it show at build time?NoClassDefFoundError/ClassNotFoundException at runtime. Gradle resolves only the named artifact successfully, so the build passes; the missing transitive classes are only discovered when code that needs them executes.
- When would you prefer exclude over isTransitive = false?When only a few specific transitive artifacts are problematic and you still want the rest of the subtree. Exclude keeps the dependency's other transitives intact, which is safer.
saying these in an interview costs you the question
- Using isTransitive = false to fix a version conflict (that's a constraint's job).
- Applying it broadly and assuming the build will warn you about missing classes.