In a multi-module build, how do you ensure all modules land in a single staging repository, and why does that matter?
answer
- apply plugin at root only
- one staging repo per build invocation
- atomic promotion of all modules
- Central immutable → broken partial release can't be fixed
- anti-pattern: per-subproject application = many repos
basics
~20 sApply the plugin once at the root project. It opens one staging repo for the whole build and injects its URL into every subproject's maven-publish, so all modules are closed and released together as one atomic release.
solid answer
~40 sApply `io.github.gradle-nexus.publish-plugin` to the **root project only** and let subprojects apply `maven-publish` + `signing`. The plugin opens a **single** staging repository per build invocation and shares its URL/id across all modules, so every module's artifacts go into the same staging repo. That matters because a multi-module library should be promoted **atomically**: you don't want module A released to Central while module B sits unreleased, leaving consumers with an incomplete, version-mismatched dependency set. With one staging repo, `closeAndReleaseSonatypeStagingRepository` validates and promotes the whole set at once. The common mistake is applying the plugin per-subproject, which opens several staging repos and breaks atomicity. If publishing only a subset, configure which publications/subprojects participate, but keep them in one staging repo.
code
kotlin · 11 lines// root build.gradle.kts — plugin applied ONCE at root
plugins {
id("io.github.gradle-nexus.publish-plugin") version "2.0.0"
}
nexusPublishing { repositories { sonatype() } }
subprojects {
apply(plugin = "maven-publish")
apply(plugin = "signing")
// configure each module's publication + signing here
}go deeper
Know the plugin goes at the root and produces one staging repo for the whole build.
Explain the URL injection into each subproject's maven-publish and why one repo means atomic release.
Discuss the immutability-driven atomicity requirement and the per-subproject anti-pattern; handle partial publishing.
Set org conventions for multi-module releases, verification gates before promotion, and recovery policy when a release partially fails.
## The atomicity requirement A library split into modules (`core`, `api`, `spring-boot-starter`, …) is released as a coherent version. Consumers expect that when version `1.4.0` appears on Central, **all** its modules are there. If module A promotes and module B fails, you've published a broken release that can't be fixed (Central is immutable) — you'd have to ship `1.4.1`. So the modules must be promoted as one unit. ## How a single staging repo achieves it The `gradle-nexus.publish-plugin` is designed to be applied at the **root**. On a build invocation it: 1. Opens **one** staging repository. 2. Holds that repo's id/URL in build state. 3. Injects that URL into each subproject's `maven-publish` `SonatypeRepository` so every `publish...ToSonatypeRepository` task uploads into the **same** repo. 4. `closeAndReleaseSonatypeStagingRepository` then closes and releases that single repo — promoting all modules atomically. ```kotlin // root build.gradle.kts plugins { id("io.github.gradle-nexus.publish-plugin") version "2.0.0" } nexusPublishing { repositories { sonatype() } } subprojects { apply(plugin = "maven-publish") apply(plugin = "signing") // each subproject defines its MavenPublication + signing } ``` ## The anti-pattern Applying the publish-plugin inside `subprojects { }` or in each module makes **each** module open its **own** staging repo. Now `close`/`release` either act on the wrong repo or you get N repos to promote individually — defeating atomicity and making the release fragile and confusing. ## Partial publishing If some modules shouldn't be published (e.g. an internal `:test-fixtures` or `:samples` module), don't apply `maven-publish` there, or skip configuring a publication. They simply won't contribute artifacts to the shared staging repo. The repo still stays single. ## Verification After `publishToSonatype`, the Nexus/Portal UI (or the plugin log) should show exactly **one** staging repository containing all expected GAV coordinates before you trigger the release.
- What goes wrong if you apply the plugin inside subprojects { } instead of at the root?Each subproject opens its own staging repository, so modules are no longer released atomically — you get multiple repos to promote individually and risk partial, unfixable releases.
- How do you exclude an internal module from publication while keeping one staging repo?Don't apply maven-publish or don't define a publication for that module; it simply contributes nothing, and the shared staging repo remains single.
Shipping a multi-module library is like releasing all volumes of a book set at once — one sealed crate (staging repo), not one crate per volume that might arrive on different days.
saying these in an interview costs you the question
- Applying the publish-plugin per-module and expecting atomic release.
- Believing a partial multi-module release can be corrected by re-publishing the same version (Central is immutable).