skip to content

Where can repositories be declared in a Gradle build, and how do project-dependency repositories differ from plugin repositories?

level: seniorimportance: should knowfreq 45%

answer

  1. two lookup paths: deps vs plugins
  2. repositories {} / dependencyResolutionManagement
  3. pluginManagement { repositories {} }
  4. gradlePluginPortal default for plugins
  5. repositoriesMode FAIL_ON_PROJECT_REPOS

basics

~10 s

Project-dependency repositories go in each project's repositories {} (or centrally in dependencyResolutionManagement in settings). Plugin repositories for the plugins {} block go in pluginManagement { repositories {} } in settings.gradle.kts. They're separate lookup paths.

solid answer

~50 s

Gradle has **two distinct repository lookup paths**. (1) **Project dependencies** declared in `dependencies {}` resolve from `repositories {}` in the build script — or, centrally, from `dependencyResolutionManagement { repositories {} }` in `settings.gradle.kts`, which applies to all projects. (2) **Plugins** applied via the `plugins {}` block resolve from repositories in `pluginManagement { repositories {} }` in `settings.gradle.kts`, where `gradlePluginPortal()` is the default. Mixing these up causes confusing failures: adding a plugin's repo to the project `repositories {}` won't help the `plugins {}` block find it. The settings-level options are the modern, preferred place to declare repositories because they centralize the trusted-source list across a multi-project build and let you enforce it with `repositoriesMode` (e.g. `FAIL_ON_PROJECT_REPOS` to forbid per-project repo declarations). The detailed mechanics of centralized repository management are a topic of their own; the key distinction to state is project-vs-plugin lookup and build-script-vs-settings placement.

code

kotlin · 8 lines
kotlin
// settings.gradle.kts
pluginManagement {
    repositories { gradlePluginPortal(); mavenCentral() }   // for plugins {} blocks
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories { mavenCentral() }                         // for dependencies {} blocks
}

go deeper

for a junior

Know plugins and dependencies use different repository blocks.

for a middle

Place plugin repos in pluginManagement and project repos in repositories{} or dependencyResolutionManagement.

for a senior

Use settings-level centralization and repositoriesMode to govern sources across a multi-project build.

for a principal

Mandate FAIL_ON_PROJECT_REPOS plus a curated central repo list as supply-chain policy; account for included builds/buildSrc.

## Two lookup paths Gradle resolves two different kinds of things, each from its own repository list: ### 1. Project dependencies What you put in `dependencies {}` (`implementation`, `api`, ...) resolves from the **project** repositories. You can declare these: - **Per project** in the build script's `repositories {}`. - **Centrally** in `settings.gradle.kts` under `dependencyResolutionManagement { repositories { ... } }`, which applies to every project in the build. ```kotlin // settings.gradle.kts dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { mavenCentral() } } ``` ### 2. Plugins Plugins applied via the `plugins { id("...") }` block resolve from the **plugin** repositories, declared in `settings.gradle.kts`: ```kotlin // settings.gradle.kts pluginManagement { repositories { gradlePluginPortal() // default mavenCentral() } } ``` `gradlePluginPortal()` is the default here. This is why a plugin can fail to resolve even though you added its repo to the project `repositories {}` — that block is the *wrong* lookup path for plugins. ## Why settings-level is preferred Declaring repositories in `settings.gradle.kts` centralizes the **trusted source list** for the whole build instead of scattering it across subprojects. `repositoriesMode` controls the interaction with per-project blocks: - `PREFER_PROJECT` (legacy default-ish): project repos override settings. - `PREFER_SETTINGS`: ignore project-declared repos, warn. - `FAIL_ON_PROJECT_REPOS`: hard-fail if any subproject declares its own — strong governance, ensures every dependency comes from the centrally-vetted set. ## Practical guidance - Put project repositories in `dependencyResolutionManagement` and plugin repositories in `pluginManagement`, both in `settings.gradle.kts`. - Reserve per-project `repositories {}` for genuinely project-specific sources, and consider `FAIL_ON_PROJECT_REPOS` to lock it down. - Remember `buildSrc` and included builds have their own settings and may need their own repo declarations. (The full feature set of centralized repository management — version catalogs, rules — is its own topic; here the load-bearing idea is *which* block resolves *what*, and *where* it lives.)

  • A plugin in the plugins {} block won't resolve even though you added its Maven repo to the project repositories {} — why?
    The `plugins {}` block resolves from `pluginManagement { repositories {} }` in settings, not the project's `repositories {}`. The plugin repo must go there.
  • What does RepositoriesMode.FAIL_ON_PROJECT_REPOS do?
    It makes the build fail if any subproject declares its own `repositories {}`, forcing all dependency sources through the centralized `dependencyResolutionManagement` list.
  • Which repository is the default for the plugins {} block?
    `gradlePluginPortal()` — automatically used unless you customize `pluginManagement { repositories {} }`.

saying these in an interview costs you the question

  • Saying the project repositories {} block resolves the plugins {} block.
  • Putting plugin repositories in build.gradle.kts and expecting plugins {} to find them.
  • Being unaware that repositories can be centralized in settings.gradle.kts.

context