How do you configure Gradle to resolve internal/company plugins alongside the public Gradle Plugin Portal?
answer
- pluginManagement.repositories in settings
- declaring replaces implicit default
- re-add gradlePluginPortal()
- internal Maven repo + credentials
- order = search precedence
basics
~10 sAdd your internal Maven repository to pluginManagement.repositories in settings, and re-add gradlePluginPortal() so both public and internal plugins resolve. Order/strategy decides precedence.
solid answer
~40 sInternal plugins live in a company Maven repository (Artifactory, Nexus, GitHub Packages), not on the public portal. To resolve them you list that repository under `pluginManagement.repositories {}` in `settings.gradle.kts`. Because declaring any repository there **replaces** the implicit default, you also explicitly add `gradlePluginPortal()` (and often `mavenCentral()`) so public plugins still resolve. Gradle searches the listed repositories in order until it finds the plugin's marker. For credentials you supply `maven { url=...; credentials { username=...; password=... } }`, typically pulled from `gradle.properties`/env vars rather than hard-coded. Internal plugins are applied by id exactly like portal plugins — `id("com.acme.build-conventions") version "1.4.0"` — once their marker is published to the internal repo. You can also use `pluginManagement.resolutionStrategy` to map ids to coordinates, but the common case is just listing the extra repository.
code
kotlin · 13 lines// settings.gradle.kts
pluginManagement {
repositories {
maven {
url = uri("https://artifactory.acme.com/plugins/")
credentials {
username = providers.gradleProperty("artifactoryUser").orNull
password = providers.gradleProperty("artifactoryToken").orNull
}
}
gradlePluginPortal()
}
}go deeper
Know internal plugins need an extra repository added; recognize the portal can still be kept.
Place the internal repo and gradlePluginPortal() under pluginManagement.repositories and explain why both are needed.
Reason about resolution order, credential handling, and the implicit-default-replacement gotcha.
Decide org-wide whether to proxy/mirror the portal behind a single internal endpoint and govern plugin provenance.
## The problem The public **Gradle Plugin Portal** only hosts public plugins. Company convention plugins (shared build logic, internal SDKs) are published to a private Maven repository instead. Gradle must be told where to look. ## Where plugin repositories are declared Plugin-resolution repositories belong in `pluginManagement.repositories {}` in **settings.gradle.kts** (not the per-project `dependencies` repositories). This block is evaluated before any project build script, so it governs how `plugins {}` ids are resolved everywhere. ```kotlin // settings.gradle.kts pluginManagement { repositories { maven { url = uri("https://nexus.acme.com/repository/maven-internal/") credentials { username = providers.gradleProperty("nexusUser").orNull password = providers.gradleProperty("nexusPassword").orNull } } gradlePluginPortal() // keep public plugins working mavenCentral() // some plugin impls live on Central } } ``` ## Why you must re-add gradlePluginPortal() In a build with **no** `pluginManagement.repositories {}` block, Gradle implicitly includes the portal. As soon as you declare your own list, that implicit entry disappears and only what you list is used. Omitting `gradlePluginPortal()` here is the classic cause of "my Spring/Kotlin plugin suddenly can't be found" after adding an internal repo. ## Resolution order Gradle searches the listed repositories **top-to-bottom** for each plugin's marker artifact and stops at the first hit. Putting the internal repo first lets internal plugins shadow public ones; putting the portal first prefers public versions. For a true single-source mirror, an org often proxies both behind one Artifactory/Nexus URL and lists only that. ## Publishing the internal plugin's marker For an internal plugin to be applied by id, its **plugin marker** (`<id>:<id>.gradle.plugin:<version>`) plus the implementation jar must exist in that internal repo. The `java-gradle-plugin` (and `maven-publish`) machinery generates the marker automatically when you publish. ## Credentials hygiene Keep usernames/tokens out of VCS — read them from `~/.gradle/gradle.properties`, environment variables, or a credentials provider. Hard-coding secrets in settings is a security red flag. ## Internal application looks identical ```kotlin plugins { id("com.acme.build-conventions") version "1.4.0" } ``` The build script can't tell whether the id came from the portal or the internal repo — only `pluginManagement` knows.
- Why do public portal plugins stop resolving once you add an internal repository?Declaring any pluginManagement repository replaces the implicit gradlePluginPortal() default. You must re-add gradlePluginPortal() explicitly to restore public resolution.
- How should credentials for the internal repo be supplied?Through gradle.properties (user-level), environment variables, or a provider — never hard-coded in settings checked into VCS.
- Does repository order matter for plugin resolution?Yes — Gradle searches listed repositories top-to-bottom for the plugin marker and stops at the first match, so order decides which source wins for a shared id.
Like adding a private package registry next to the public npm one: you must keep the public registry in the list too, or only your private packages resolve.
saying these in an interview costs you the question
- Adding the internal repo to the per-project dependencies repositories block instead of pluginManagement.
- Forgetting to re-add gradlePluginPortal() and then concluding the portal is 'broken'.
- Hard-coding repository credentials in settings.gradle.kts.