In the absence of attribute-aware metadata, what is the 'default' configuration of a project, and how does it relate to project(':lib') versus project(path: ':lib', configuration: 'default')?
answer
- 'default' = implicit legacy consumable config
- project(':lib') == configuration 'default' historically
- java wired default extendsFrom runtimeElements
- variant-aware resolution now bypasses default
- default survives as fallback for no-metadata producers
basics
~10 sLegacy project dependencies resolve to a configuration literally named 'default'. project(':lib') is shorthand for project(path: ':lib', configuration: 'default') only when no variant-aware metadata drives selection.
solid answer
~50 sHistorically, a bare `project(':lib')` meant "consume the configuration named `default`" — that's why every project implicitly had a `default` configuration, and `project(':lib')` was literally shorthand for `project(path: ':lib', configuration: 'default')`. The `java` plugin wired `default` to extend `runtimeElements` so depending on a Java project gave you its runtime. With modern **variant-aware resolution** (Gradle Module Metadata, `apiElements`/`runtimeElements`, attributes), the `default` configuration is largely bypassed: a plain `project(':lib')` now selects a *variant* by matching attributes, not by reading a configuration literally named `default`. The `default` configuration still exists as a fallback for producers without proper variant metadata. So in interviews: explain that `project(configuration: 'default')` is the explicit legacy form, that it's a fallback, and that on a normal `java-library` producer attribute matching takes over — which is why you can get the API variant on the compile classpath rather than the broad runtime that legacy `default` gave.
code
kotlin · 7 lines// legacy explicit form (rarely needed on modern java projects)
dependencies {
implementation(project(path = ":lib", configuration = "default"))
}
// modern: attributes pick apiElements/runtimeElements per context
dependencies { implementation(project(":lib")) }go deeper
Recall that there is a 'default' configuration and that bare project(':lib') historically meant it.
Explain the shift from name-based 'default' to attribute-driven variant selection and that default is now a fallback.
Discuss how java-library's apiElements/runtimeElements supersede default and why explicitly targeting default is usually a smell.
Advise on migrating legacy name-based wiring to attribute/variant modeling and the implications for cross-project and published consumption.
## The historical model Before variant-aware resolution, project dependencies were resolved by **configuration name**. Each project had an implicit configuration called `default`, and: ```kotlin project(":lib") == project(path = ":lib", configuration = "default") ``` The `java` plugin made `default` `extendsFrom(runtimeElements)`, so a Java project's `default` exposed its runtime classpath + runtime jar. That's why old multi-project builds 'just worked' — depending on a sibling pulled its runtime. ## What changed Gradle introduced **variant-aware resolution**: producers describe their outputs as *variants* (consumable configurations carrying attributes like `org.gradle.usage`), and consumers select by **attribute matching** rather than by the literal name `default`. The `java-library` plugin publishes: - `apiElements` — `usage = java-api` (compile-time surface) - `runtimeElements` — `usage = java-runtime` (runtime surface) Now `project(":lib")` on a `compileClasspath` matches `apiElements`; on a `runtimeClasspath` it matches `runtimeElements`. The literal `default` configuration is **not** consulted when variant metadata is available. ## Where `default` still matters It remains a **fallback**: if a producer has no variant-aware metadata (e.g. a bare project applying no Java plugin, or relying on legacy ivy-style outputs), Gradle can still fall back to the `default` configuration. You can also still target it explicitly: ```kotlin implementation(project(path = ":lib", configuration = "default")) ``` but that opts out of attribute-driven selection and is rarely what you want on a modern Java project — you'd lose the api/runtime distinction. ## Interview-ready summary - `default` = the historical implicit consumable configuration. - `project(':lib')` was shorthand for consuming `default`; now it's attribute-driven when metadata exists. - Explicitly naming `default` reverts to legacy behavior and is generally a smell on attribute-aware producers.
- On a java-library producer, why does project(':lib') no longer simply read the 'default' configuration?Because variant-aware resolution matches consumer attributes (java-api vs java-runtime) against apiElements/runtimeElements. The literal 'default' configuration is bypassed when proper variant metadata exists.
- When is the 'default' configuration still used?As a fallback for producers lacking variant-aware metadata, or when you explicitly target configuration = 'default' to opt back into legacy behavior.
saying these in an interview costs you the question
- Claiming project(':lib') always reads a configuration literally named 'default' on modern builds.
- Saying the default configuration was removed — it still exists as a fallback.