How do you exclude a single transitive dependency that is pulled in by one specific dependency in Gradle?
answer
- exclude inside the dependency closure
- group and/or module — never version
- scoped to one dependency's subgraph
- other paths can still pull it in
- most surgical option
basics
~10 sAttach an exclude block to that one dependency, naming the unwanted artifact by group and/or module. Only that dependency's transitive graph is affected.
solid answer
~40 sUse the per-dependency `exclude` form so the exclusion is scoped to one declared dependency rather than the whole project. In the dependencies block you call `implementation("com.acme:foo:1.0") { exclude(group = "org.slf4j", module = "slf4j-simple") }`. Both keys are optional: `group` alone drops every module from that group brought in transitively by `foo`; `module` alone drops that module regardless of group; together they pin one coordinate. This is the most surgical exclusion — it does not touch what other dependencies bring in, so if a second library also pulls `slf4j-simple`, it survives. Prefer this over broad rules when only one path is problematic, and document why with a comment or a `because(...)` reason so the next person understands the intent.
code
kotlin · 8 linesdependencies {
implementation("com.acme:foo:1.0") {
// drop one coordinate
exclude(group = "org.slf4j", module = "slf4j-simple")
// drop a whole group transitively pulled by foo
exclude(group = "commons-logging")
}
}go deeper
Know the syntax: exclude(group, module) inside the dependency block, and that group/module are the keys.
Explain the scoping: it only affects this dependency's transitive subgraph, so duplicate paths can still bring it in.
Contrast per-dependency vs configuration-wide excludes and pick the right granularity; pair with because() for documentation.
Set team conventions: prefer constraints/platform alignment over scattered excludes, and require documented reasons so the graph stays auditable.
## What "transitive" means When you declare a dependency like `com.acme:foo:1.0`, Gradle reads its published metadata (a Gradle Module Metadata `.module` file or a Maven `.pom`) and automatically resolves everything `foo` itself depends on. Those second-, third-, ... order dependencies are **transitive dependencies**. They make adding a library convenient, but they sometimes drag in things you don't want: a conflicting logging backend, a vulnerable version, or a duplicate of something you already provide. ## Per-dependency exclude The narrowest tool is an `exclude` attached to a *single* dependency declaration: - `exclude(group = "...")` — drop everything from that Maven group that **this** dependency pulls in transitively. - `exclude(module = "...")` — drop that module name regardless of group. - both — pin exactly one `group:module` coordinate. Note you exclude by **group and module, never by version** — Gradle removes the node from the graph entirely; you don't say "exclude version 1.2". ## Scope The key property is **scope**: the rule only prunes the subgraph reachable *through that one declared dependency*. If module `bar` (declared separately) also brings the excluded artifact, it still arrives. That makes per-dependency exclude precise but also means it can silently fail to remove an artifact when multiple paths supply it. ## When to reach for it Use it when exactly one library is responsible for the unwanted transitive — e.g. a library that bundles `slf4j-simple` while your app uses Logback. For a project-wide problem (the same junk arrives through many paths), a `configurations.all { exclude(...) }` rule is more appropriate. ```kotlin dependencies { implementation("com.acme:foo:1.0") { exclude(group = "org.slf4j", module = "slf4j-simple") because("foo bundles slf4j-simple, but we log through Logback") } } ```
- If two libraries each transitively pull slf4j-simple and you only exclude it on one, what happens?It still ends up on the classpath via the second library. Per-dependency exclude only prunes the subgraph of the dependency it's attached to; you'd need to exclude on both, or use a configuration-wide rule.
- Can you exclude by version?No. Excludes operate on group/module coordinates and remove the node entirely. To force a specific version you use a different mechanism (a constraint or `resolutionStrategy.force` / strict version).
saying these in an interview costs you the question
- Claiming exclude takes a version argument.
- Assuming a per-dependency exclude removes the artifact globally even when another dependency supplies it.