skip to content

You try to resolve `implementation` and get an error that it cannot be resolved. Why, and what should you resolve instead?

level: juniorimportance: must knowfreq 50%

answer

  1. implementation = bucket, not resolvable
  2. isCanBeResolved = false
  3. resolve compileClasspath / runtimeClasspath
  4. extendsFrom inherits the bucket
  5. declare vs resolve roles

basics

~10 s

implementation is a declaration bucket — isCanBeResolved is false — so it has no resolution result. Resolve compileClasspath or runtimeClasspath, which extend from it.

solid answer

~40 s

`implementation` is a **dependency-scope bucket**: both `isCanBeResolved` and `isCanBeConsumed` are false. Its only job is to *hold* declared dependencies, not to produce a file set, so asking for its resolved artifacts errors with 'Resolving configuration 'implementation' directly is not allowed'. The configurations you actually resolve are `compileClasspath` and `runtimeClasspath`, which are resolvable and `extendsFrom` the relevant buckets (`implementation`, `compileOnly`/`runtimeOnly`, `api`). So if you need the files, ask the right resolvable configuration — e.g. `configurations.runtimeClasspath.get().resolve()` or wire a task input to it. This protects you from accidentally resolving a half-defined set and from the classic mistake of treating one configuration as both the place you declare and the thing you resolve.

code

kotlin · 5 lines
kotlin
// WRONG: implementation is a bucket
// configurations.implementation.get().resolve()  // ERROR

// RIGHT: resolve the resolvable sibling
val runtimeFiles = configurations.runtimeClasspath.get().resolve()

go deeper

for a junior

Recognize that buckets can't be resolved and name compileClasspath/runtimeClasspath as the right targets.

for a middle

Explain the flag mechanics and the extendsFrom inheritance that feeds the classpath.

for a senior

Push toward lazy wiring (Provider as task input) instead of eager .resolve(); tie to configuration cache.

for a principal

Use this to justify role discipline in convention plugins so build authors never resolve buckets across the org.

## The error Gradle refuses `configurations.implementation.get().resolve()` (or `.files`) with a message like *'Resolving configuration 'implementation' directly is not allowed'*. This is by design. ## Why Every configuration has two booleans: - `isCanBeResolved` — may Gradle compute artifacts for it? - `isCanBeConsumed` — may other projects depend on it? A **bucket** (dependency-scope) like `implementation` has *both false*. It exists only so you can write `dependencies { implementation("...") }`. Resolving means running dependency resolution + variant selection to get concrete files — a bucket deliberately has no such result. ## What to resolve instead The Java plugin creates resolvable configurations that inherit the buckets: - `compileClasspath` — resolvable; `extendsFrom(implementation, compileOnly, api, ...)`. - `runtimeClasspath` — resolvable; `extendsFrom(implementation, runtimeOnly, api, ...)`. So declare in the bucket, resolve the classpath: ```kotlin val files = configurations.runtimeClasspath.get().resolve() // OK ``` ## Wiring into tasks (preferred) Rather than calling `.resolve()` eagerly, wire the resolvable configuration as a task input so resolution is lazy and cache-friendly: ```kotlin tasks.register("listRuntime") { val cp = configurations.runtimeClasspath doLast { cp.get().forEach { println(it.name) } } } ``` ## Takeaway 'Cannot be resolved' is not a bug — it tells you that you reached for the *declaration* role when you wanted the *resolution* role. Pick the resolvable sibling.

  • How does `runtimeClasspath` get the dependencies you declared in `implementation`?
    Through `extendsFrom`: `runtimeClasspath` extends `implementation` (and `runtimeOnly`, `api`, etc.), so declarations in the bucket flow up into the resolvable configuration.
  • Is there a downside to calling `.resolve()` directly in configuration scripts?
    Yes — it triggers eager resolution at configuration time, hurting performance and configuration cache. Prefer wiring the configuration (a Provider) as a lazy task input.

saying these in an interview costs you the question

  • Claiming the error is a Gradle bug or a missing dependency.
  • Trying to flip `isCanBeResolved = true` on `implementation` to 'fix' it instead of resolving the right configuration.

context