skip to content

What is the difference between running the aggregate `publish` task and a specific publish<Pub>PublicationTo<Repo>Repository task?

level: seniorimportance: should knowfreq 45%

answer

  1. publish = lifecycle, depends on all remote publishes
  2. granular = one pub × one repo
  3. publish excludes mavenLocal
  4. pin CI to specific task
  5. new repo silently joins publish

basics

~10 s

publish is a lifecycle task that fans out to every publication-to-remote-repository task, pushing to all configured remote repos. A specific publish<Pub>PublicationTo<Repo>Repository task targets exactly one publication and one repository.

solid answer

~40 s

`publish` is an **aggregate lifecycle task** with no action of its own; the plugin makes it depend on **every** generated `publish<Pub>PublicationTo<Repo>Repository` task. So running `./gradlew publish` uploads all publications to all declared remote repositories at once — convenient locally, but risky in CI where you usually want a single target (e.g., snapshots vs releases, or staging vs production). The granular task `publish<Pub>PublicationTo<Repo>Repository` scopes the upload to exactly one publication and one repo, which is what you wire into release pipelines. Note `publish` covers only remote repositories; the local install fan-out is the separate `publishToMavenLocal` aggregate. To publish a subset, target the specific tasks or filter the repository set by environment in the build script.

code

bash · 5 lines
bash
# fans out to every remote repo + publication:
./gradlew publish

# scoped to exactly one target (preferred in CI):
./gradlew publishMavenJavaPublicationToReleasesRepository

go deeper

for a junior

Know publish pushes to remote repos and there are per-target tasks too.

for a middle

Explain the aggregate-to-granular dependency fan-out and that publish excludes mavenLocal.

for a senior

Design pipelines that target specific publish tasks or conditionally declare repos to avoid accidental multi-repo pushes.

for a principal

Set org-wide release conventions: pin CI to explicit publish targets, gate snapshot vs release repos, and audit repository declarations to prevent dual-publishing.

## Aggregate vs granular The `maven-publish` plugin builds a dependency graph of publish tasks: - **Granular**: `publish<Pub>PublicationTo<Repo>Repository` — one publication → one remote repo. This is the unit of real work (it uploads). - **Aggregate**: `publish` — a **lifecycle task** that `dependsOn` every granular remote-publish task. It performs no upload itself; it just triggers all of them. - **Aggregate (local)**: `publishToMavenLocal` — the parallel aggregate for `...ToMavenLocal` install tasks. `publish` does **not** include local install. ## Why this matters for release engineering If you declare both a snapshots repo and a releases repo, `./gradlew publish` will try to push to **both**. In a pipeline you almost always want exactly one target chosen by context. Two common strategies: 1. **Target the specific task**: `./gradlew publishMavenJavaPublicationToReleasesRepository` — explicit, no surprises. 2. **Conditionally declare repositories**: only add the releases repo when the version is non-SNAPSHOT, so the aggregate `publish` naturally resolves to the right place. ```kotlin publishing { repositories { maven { name = if (version.toString().endsWith("SNAPSHOT")) "snapshots" else "releases" url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotUrl else releaseUrl) } } } ``` ## Discoverability `./gradlew tasks --group publishing` lists the aggregates and every granular task, so a pipeline author can pick the precise task name rather than guessing. ## Gotcha Because `publish` is an alias for 'everything remote', a newly added repository silently joins it. Pinning CI to specific task names protects releases from accidental dual-publishing.

  • Does `publish` also install to ~/.m2?
    No. Local install is the separate publishToMavenLocal aggregate; `publish` covers only declared remote repositories.
  • Why prefer the specific task in a release pipeline?
    It guarantees exactly one target, so adding another repo later can't silently cause a dual/accidental publish.
  • How can you keep `publish` correct while still using it?
    Conditionally declare only the appropriate repository per build (e.g., snapshots vs releases by version), so the aggregate resolves to one target.

publish is the 'send to all' button; the granular task is addressing one specific recipient. In production you want to address the recipient, not blast everyone.

saying these in an interview costs you the question

  • Claiming `publish` pushes to a single repo — it fans out to all remote repositories.
  • Believing `publish` performs the upload directly — it's a lifecycle task delegating to granular tasks.
  • Assuming `publish` includes mavenLocal install.

context