skip to content

What's the difference between the foojay-resolver and foojay-resolver-convention plugin IDs, and which do you apply where?

level: middleimportance: should knowfreq 40%

answer

  1. two IDs, same project
  2. convention auto-wires javaRepositories
  3. bare resolver = manual wiring
  4. settings.gradle.kts only
  5. ordering when multiple resolvers

basics

~10 s

Both come from the same project. foojay-resolver only registers the resolver, so you must wire toolchainManagement yourself. foojay-resolver-convention registers the resolver AND wires up the default javaRepositories for you. You apply either in settings.gradle.kts.

solid answer

~40 s

The Foojay toolchains plugin publishes two IDs. **`org.gradle.toolchains.foojay-resolver`** registers the Disco resolver as a `JavaToolchainRepository` but leaves you to declare it inside `toolchainManagement { jvm { javaRepositories { repository("foojay") { resolverClass = ... } } } }`. **`org.gradle.toolchains.foojay-resolver-convention`** is a thin convention layer: it applies the base plugin and then auto-registers the foojay repository with the default ordering, so a single `plugins { id("...convention") version "..." }` line is all you need. Both go in **`settings.gradle.kts`** (not `build.gradle.kts`) because `toolchainManagement` is a settings-level block. In practice almost everyone uses the convention variant; you'd drop to the bare `foojay-resolver` only when you want to control repository ordering or combine multiple resolvers.

code

kotlin · 5 lines
kotlin
// settings.gradle.kts
// Convention: one line, auto-registers the foojay repository
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
}

go deeper

for a junior

Know the convention plugin is the one-liner you normally add to settings.

for a middle

Distinguish the two IDs and explain what the convention layer auto-wires.

for a senior

Explain repository ordering with multiple resolvers and why this is settings-scoped like dependencyResolutionManagement.

for a principal

Decide org policy: standard convention everywhere vs. internal resolver first + foojay fallback for air-gapped/controlled sourcing.

## Two plugin IDs, one project The community-maintained `foojay-toolchains` project publishes **two** plugin IDs to the Gradle Plugin Portal: | ID | What it does | |----|--------------| | `org.gradle.toolchains.foojay-resolver` | Registers the foojay Disco resolver class so it *can* be referenced, but does **not** wire it into any repository list. | | `org.gradle.toolchains.foojay-resolver-convention` | Applies the base resolver **and** auto-registers it in `toolchainManagement.jvm.javaRepositories` with default ordering — zero extra config. | ## Why this is a settings-level concern Toolchain *provisioning sources* are configured under the **`toolchainManagement`** block, which lives in **`settings.gradle.kts`**, not in a project's `build.gradle.kts`. This mirrors how `dependencyResolutionManagement` and `pluginManagement` are settings-level — they apply across the whole build. ```kotlin // settings.gradle.kts — convention (recommended) plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" } ``` ## The manual (non-convention) form If you apply the bare `foojay-resolver`, you must declare the repository yourself: ```kotlin // settings.gradle.kts — manual wiring plugins { id("org.gradle.toolchains.foojay-resolver") version "0.9.0" } toolchainManagement { jvm { javaRepositories { repository("foojay") { resolverClass = org.gradle.toolchains.foojay.FoojayToolchainResolver::class.java } } } } ``` ## When to choose which - **Convention**: the default for almost all builds — least ceremony. - **Bare resolver**: when you have **multiple** toolchain resolvers and need explicit ordering (Gradle tries repositories in declared order), or when an org provides its own internal resolver and foojay is a fallback. ## Common mistake Applying the plugin in `build.gradle.kts` instead of `settings.gradle.kts` — it won't take effect, because `toolchainManagement` doesn't exist at project scope.

  • Why must the plugin go in settings.gradle.kts rather than build.gradle.kts?
    Because toolchain provisioning sources are configured under the settings-level `toolchainManagement` block, which doesn't exist at project scope.
  • When would you prefer the bare foojay-resolver over the convention variant?
    When you register multiple toolchain resolvers and need explicit ordering, or layer an internal org resolver ahead of foojay as a fallback.

saying these in an interview costs you the question

  • Saying the two IDs are unrelated or from different vendors.
  • Putting the plugin in build.gradle.kts and expecting provisioning to work.

context