Why are -SNAPSHOT versions treated specially, and what does that mean for caching and for publishing the same version repeatedly?
answer
- -SNAPSHOT = mutable changing module
- snapshot repo accepts overwrites
- release repo rejects republish, immutable
- cacheChangingModulesFor default 24h
- local ~/.m2 overwrites both
basics
~10 sA -SNAPSHOT version is a mutable, 'changing' module: re-publishing the same coordinate is allowed and expected, and Gradle periodically re-checks it instead of caching forever. Release versions are immutable and cannot be overwritten.
solid answer
~40 sThe `-SNAPSHOT` suffix marks a version as **mutable** — Gradle treats it as a *changing module*. Practically: (1) you may publish `1.0.0-SNAPSHOT` over and over, and a snapshot repository accepts each overwrite (often storing timestamped builds and serving the latest); (2) on the consumer side Gradle doesn't trust its cache indefinitely — `cacheChangingModulesFor` (default 24h) bounds how long a cached snapshot is reused before re-checking the source. A **release** version (no suffix) is the opposite: immutable. A well-configured release repo rejects republishing an existing version, which guarantees reproducibility — `1.0.0` means the same bytes forever. This duality is exactly why publishing routes on `version.endsWith('-SNAPSHOT')`: mutable builds belong in the snapshots URL, immutable ones in the releases URL. For local publishing, `~/.m2` happily overwrites both, so the safety only really applies to remote release repos.
code
kotlin · 6 linesconfigurations.all {
resolutionStrategy {
// Pick up the freshest snapshot on every build
cacheChangingModulesFor(0, "seconds")
}
}go deeper
Know -SNAPSHOT means in-progress/mutable and releases are final.
Explain overwrite semantics and that snapshots are re-checked rather than cached forever.
Tie cacheChangingModulesFor, --refresh-dependencies, and immutability to the publish-URL routing decision.
Define retention/immutability governance: locked release repos, snapshot cleanup policy, and reproducibility guarantees.
## What '-SNAPSHOT' signals The suffix is a convention shared by Maven and Gradle meaning **this version is still in progress and may change**. Gradle classifies such modules as *changing modules*. ## Consequences for publishing - **Snapshot repos accept overwrites.** Publishing `1.0.0-SNAPSHOT` repeatedly is normal; the server typically retains timestamped artifacts and serves the newest. CI nightly builds rely on this. - **Release repos reject overwrites.** Publishing `1.0.0` a second time fails (or should, under a properly locked release repo). This enforces immutability and reproducibility — the cornerstone of trustworthy dependency resolution. ## Consequences for consuming (caching) For a changing module, Gradle won't cache forever: ```kotlin configurations.all { resolutionStrategy { cacheChangingModulesFor(0, "seconds") // always re-check snapshots } } ``` Default is 24 hours. Lower it (even to 0) when you need the very latest snapshot every build; raise it to reduce network chatter. `--refresh-dependencies` forces an immediate re-check regardless. Releases, being immutable, are cached indefinitely — there's no reason to re-fetch bytes that can't change. ## Why this drives the publish routing Because mutability differs, the two go to different URLs. The conditional `version.endsWith('-SNAPSHOT')` is the switch: ```kotlin url = if (version.toString().endsWith("-SNAPSHOT")) snapshotsUrl else releasesUrl ``` ## Local repo caveat `publishToMavenLocal` into `~/.m2` does **not** enforce immutability — it overwrites releases just as freely as snapshots. So the immutability guarantee is a property of remote release repositories, not of local publishing. This is one more reason not to treat `mavenLocal` as a source of truth for release reproducibility.
- How do you force Gradle to re-fetch a snapshot immediately?Run with `--refresh-dependencies`, which ignores cached metadata, or set `cacheChangingModulesFor(0, ...)` so changing modules are always re-checked.
- Why can you re-publish a snapshot but not a release?Snapshots are mutable by convention and the snapshot repo accepts overwrites; a release repo enforces immutability, so republishing the same version is rejected to preserve reproducibility.
A snapshot is a whiteboard you keep rewriting; a release is ink on a signed contract — once written, it doesn't change.
saying these in an interview costs you the question
- Saying releases can be overwritten on a properly configured release repo.
- Assuming ~/.m2 enforces release immutability — it does not.