skip to content

How does Gradle decide whether to publish to a snapshot or a release repository, and what role does the -SNAPSHOT suffix play?

level: middleimportance: must knowfreq 60%

answer

  1. -SNAPSHOT = mutable / in-dev
  2. release = immutable
  3. Gradle doesn't auto-route — you pick URL
  4. endsWith("SNAPSHOT") ? snapshots : releases
  5. consumer: changing module, 24h cache

basics

~20 s

A version ending in -SNAPSHOT is a snapshot; anything else is a release. Gradle itself doesn't pick the repo — you point publishing at a snapshot or release URL, typically choosing based on whether version ends with -SNAPSHOT.

solid answer

~40 s

The `-SNAPSHOT` suffix is a Maven convention meaning "mutable, in-development version". Repositories treat snapshots specially: they allow re-uploading the same coordinate and often timestamp each upload, whereas release repos are immutable. Gradle's `maven-publish` does **not** auto-route based on the suffix — you declare one or more `repositories { maven { url = ... } }` targets, and you typically pick the URL conditionally: if `version.endsWith("-SNAPSHOT")` use the snapshot URL, else the release URL. Many corporate repos (Nexus/Artifactory) expose separate snapshot and release endpoints precisely so the build chooses by version. On the consumer side, Gradle resolves `-SNAPSHOT` dependencies as changing modules with a 24-hour cache TTL by default. So the suffix drives semantics (mutability, caching) but the routing logic is yours to write.

code

kotlin · 8 lines
kotlin
repositories {
    maven {
        url = if (version.toString().endsWith("SNAPSHOT"))
            uri("https://repo.acme.com/snapshots")
        else
            uri("https://repo.acme.com/releases")
    }
}

go deeper

for a junior

Know that -SNAPSHOT means in-development/mutable and a plain version means a release.

for a middle

Explain that you write the snapshot-vs-release URL selection yourself off the version string, plus repo write rules.

for a senior

Cover consumer-side changing-module caching, reproducibility risks of snapshot deps, and credential handling per endpoint.

for a principal

Define org-wide promotion policy: who can push releases, snapshot retention, immutability guarantees, and CI gating.

## What a SNAPSHOT version is In the Maven ecosystem a version string ending in `-SNAPSHOT` (e.g. `2.0.0-SNAPSHOT`) is a **mutable, pre-release** identity. It means: "this is the current development state of 2.0.0, and its contents may change without the version string changing." A plain version like `2.0.0` is a **release** — immutable once published. This distinction matters in three places: 1. **Repository write rules.** Snapshot repositories permit overwriting the same coordinate repeatedly (and usually store timestamped sub-versions). Release repositories reject re-publishing an existing coordinate. 2. **Consumer caching.** Gradle treats `-SNAPSHOT` dependencies as *changing modules*: it re-checks the remote up to once every 24 hours by default (`cacheChangingModulesFor`). 3. **Promotion workflow.** Teams develop against `-SNAPSHOT`, then drop the suffix to cut a release. ## Gradle does not auto-route Unlike Maven's `distributionManagement`, Gradle's `maven-publish` plugin will publish a publication to **whatever repository(ies) you declare**. There is no built-in "if snapshot then snapshotRepo" rule. You implement it yourself by choosing the URL based on the version: ```kotlin publishing { publications { create<MavenPublication>("lib") { from(components["java"]) } } repositories { maven { val releases = uri("https://repo.acme.com/releases") val snapshots = uri("https://repo.acme.com/snapshots") url = if (version.toString().endsWith("SNAPSHOT")) snapshots else releases credentials { username = providers.gradleProperty("repoUser").orNull password = providers.gradleProperty("repoPassword").orNull } } } } ``` Because `version` here is `project.version`, the convention is to drive the whole decision off the project version string. ## Why teams keep release and snapshot endpoints separate - Different retention/cleanup policies (snapshots are garbage-collected; releases are kept forever). - Different permissions (anyone can push snapshots; only CI can push releases). - Immutability guarantees for releases so a built artifact never silently changes. ## Gotchas - Forgetting the suffix while iterating means re-pushing to a release repo, which the repo will reject (or, worse, you mutate a "release"). - Mixing snapshot and release dependencies makes builds non-reproducible because the snapshot content can drift between builds.

  • On the consumer side, how does Gradle treat a -SNAPSHOT dependency differently?
    It treats it as a changing module and re-checks the remote at most once per 24 hours by default; you can tune this with resolutionStrategy.cacheChangingModulesFor.
  • Why do release repositories reject re-publishing an existing version?
    Releases are immutable so a coordinate always maps to identical bytes; allowing overwrite would break reproducibility and trust.
  • Does maven-publish read the -SNAPSHOT suffix to choose a repository automatically?
    No. You declare the repositories and write the conditional URL logic yourself based on the version string.

saying these in an interview costs you the question

  • Saying Gradle automatically routes snapshots to a snapshot repo like Maven's distributionManagement — it does not.
  • Claiming snapshot and release artifacts are equally immutable.

context