skip to content

What does the publishToMavenLocal task do, and where does it put your artifacts?

level: juniorimportance: must knowfreq 70%

answer

  1. ~/.m2/repository
  2. aggregate over publish<Pub>...ToMavenLocal
  3. equivalent to mvn install
  4. resolved via mavenLocal()
  5. local dev only

basics

~10 s

publishToMavenLocal installs every publication into your local Maven repository on disk (by default ~/.m2/repository), so other local builds can resolve it via mavenLocal().

solid answer

~40 s

When you apply the `maven-publish` plugin and declare publications, Gradle generates a `publishToMavenLocal` task. Running it builds the artifacts (jars), generates the POM, and copies them into the local Maven repository — by default `~/.m2/repository`, honoring a custom `<localRepository>` in `settings.xml`. It is an aggregate task that depends on one `publish<Pub>PublicationToMavenLocal` task per publication. You use it during local development to test consumption from another build that declares `mavenLocal()`, without touching a remote/shared repository. It is the Gradle equivalent of Maven's `mvn install`. The local repo isn't safe for CI sharing — it's per-machine and unversioned, so treat it as a developer convenience only.

code

bash · 2 lines
bash
./gradlew publishToMavenLocal
# installs under ~/.m2/repository/<group>/<artifact>/<version>/

go deeper

for a junior

Know it installs to ~/.m2/repository and is like 'mvn install' for local testing.

for a middle

Explain it's an aggregate over per-publication ...ToMavenLocal tasks and how mavenLocal() resolves it.

for a senior

Discuss the staleness/poisoning risks of mavenLocal() and why it's unfit for CI sharing.

for a principal

Frame local install as a dev-only loop; mandate proper internal repositories (snapshots/releases) for cross-team artifact sharing instead of relying on M2.

## Where the task comes from The `maven-publish` plugin reacts to each `MavenPublication` you register in the `publishing { publications { } }` block and **lazily generates a fixed set of tasks**. One of them is `publishToMavenLocal`. ## What it does `publishToMavenLocal` is an **aggregate (lifecycle) task**: it does no work itself but depends on one concrete task per publication, named `publish<PubName>PublicationToMavenLocal`. Each of those: 1. Builds the artifacts attached to the publication (typically the `jar`). 2. Generates the POM (via the corresponding `generatePomFileFor<PubName>Publication` task it depends on). 3. Lays all of that out under the **local Maven repository** in the standard Maven layout (`group/artifact/version/...`). ## Where it writes The local Maven repository is `~/.m2/repository` by default. If a `~/.m2/settings.xml` sets `<localRepository>`, that path is honored. This is the same directory `mvn install` writes to, which is why a consuming build that declares `repositories { mavenLocal() }` can then resolve your module. ## When to use it vs `publish` - `publishToMavenLocal` → local-only, for testing consumption on the same machine. - `publish` → pushes to every **defined remote repository** (`publishing { repositories { maven { url … } } }`). ## Gotcha `mavenLocal()` is **not** a normal cache — it is a real repository Gradle will resolve from, and stale/overwritten snapshots there can poison other builds. Use it deliberately, prefer unique versions, and clear it when results look wrong. ```kotlin plugins { `maven-publish` } publishing { publications { create<MavenPublication>("lib") { from(components["java"]) } } } // generates: publishLibPublicationToMavenLocal (and the aggregate publishToMavenLocal) ```

  • How can you change where publishToMavenLocal writes?
    Set <localRepository> in ~/.m2/settings.xml; Gradle's mavenLocal() and the install task both honor it. There's no per-project Gradle DSL override for the M2 location.
  • Why might a consuming build still pick up a stale version after publishToMavenLocal?
    mavenLocal() is a real repository, not a cache; a released (non-SNAPSHOT) version isn't re-fetched, so the old artifact lingers. Bump the version or delete the local entry.

Like copying a build into a shared drawer on your own desk so your other projects can grab it — convenient, but nobody else's machine can see that drawer.

saying these in an interview costs you the question

  • Claiming it pushes to a remote repository — it only writes to the local Maven repo.
  • Confusing ~/.m2/repository with Gradle's own dependency cache (~/.gradle/caches/modules-2) — different stores.

context