skip to content

GAV Coordinates and Versioning

Setting groupId, artifactId, and version on a publication, routing SNAPSHOTs correctly, and using versionMapping to publish resolved versions. Interviewers ask about versionMapping because otherwise a consumer inherits your dynamic versions.

on this pageshow

questions

5

How do you set the groupId, artifactId, and version on a MavenPublication, and how does that relate to project.group and project.version?

level: juniorimportance: must knowfreq 70%

answer

  1. groupId / artifactId / version
  2. defaults: project.group, project.name, project.version
  3. override per-publication
  4. multiple artifacts from one project
  5. override != mutating project.version

basics

~10 s

Inside a MavenPublication you set groupId, artifactId, and version directly. If you omit them, Gradle defaults groupId to project.group, version to project.version, and artifactId to project.name.

solid answer

~30 s

A `MavenPublication` carries three coordinate properties: `groupId`, `artifactId`, and `version`. When you don't set them, Gradle derives defaults — `groupId` from `project.group`, `version` from `project.version`, and `artifactId` from `project.name`. You can override any of them inside the publication block, which is common when one project produces several artifacts (e.g. a `-core` and a `-bom`) or when the published name should differ from the Gradle project name. Overriding here does **not** change `project.group`/`project.version`; it only affects this publication's published coordinates and the generated POM's `<groupId>/<artifactId>/<version>`. Setting `project.group`/`project.version` at the top level is the idiomatic way when all publications share one GAV.

code

kotlin · 10 lines
kotlin
publishing {
    publications {
        create<MavenPublication>("library") {
            from(components["java"])
            groupId = "com.acme"
            artifactId = "payments-core"
            version = "1.4.0"
        }
    }
}

go deeper

for a junior

Name the three coordinates and the three project defaults they fall back to.

for a middle

Explain when to override per-publication (multiple artifacts, BOMs, renamed modules) and that artifactId defaults to project.name.

for a senior

Discuss keeping GAV centralized on the project vs. per-publication, and lazy evaluation gotchas when reading project.version early.

for a principal

Frame GAV as the public API contract of a module and how org conventions (reverse-DNS groups, naming) are governed across many publishing builds.

## What "GAV" means Every artifact in a Maven-style repository is addressed by three coordinates, collectively called **GAV**: - **G**roup id — a namespace, usually reverse-DNS (`com.acme`). - **A**rtifact id — the module name (`payments-core`). - **V**ersion — the release identity (`1.4.0`, `2.0.0-SNAPSHOT`). A consumer declares `com.acme:payments-core:1.4.0`, so these three strings are the public contract of what you publish. ## Where coordinates come from in Gradle The `maven-publish` plugin contributes a `publishing { publications { ... } }` block. Inside a `MavenPublication` you can assign coordinates explicitly: - `groupId`, `artifactId`, `version` are mutable `String` properties on the publication. - If you leave them unset, Gradle fills in **defaults at publish time**: `groupId = project.group.toString()`, `version = project.version.toString()`, `artifactId = project.name`. So for the common case you set nothing on the publication and instead set `group` and `version` once on the project — every publication inherits them. ## When you override on the publication You override directly on the `MavenPublication` when a single Gradle project emits **more than one** set of coordinates, or when the published name must diverge from the project's folder name. Classic cases: - A BOM published as `acme-bom` from a project whose `project.name` is `bom`. - A renamed artifact for backward compatibility. - Multiple publications in one project, each with its own artifactId. Overriding the publication's `version` does **not** mutate `project.version`; the two are independent once you set the publication value explicitly. ## Example ```kotlin publishing { publications { create<MavenPublication>("library") { from(components["java"]) // override only what differs from project defaults: groupId = "com.acme" artifactId = "payments-core" version = "1.4.0" } } } ``` ## Pitfalls - Coordinates are resolved lazily; if you read `project.version` too early in configuration you may capture a stale value. - `artifactId` defaults to `project.name`, which is the **directory name** unless overridden in `settings.gradle(.kts)` — a frequent surprise.

  • If you set project.group and project.version but nothing on the publication, what coordinates get published?
    groupId = project.group, version = project.version, artifactId = project.name (the directory name unless overridden in settings).
  • Why might artifactId differ from what you expect even with no override?
    Because it defaults to project.name, which is the project directory name, not necessarily the human-friendly module name; it must be set in settings.gradle if you want a different one.

saying these in an interview costs you the question

  • Claiming you must always set coordinates explicitly on every publication — defaults from project.group/name/version usually suffice.
  • Thinking overriding the publication's version also changes project.version.

context

open as a page

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%

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.

open as a page

You produce two artifacts (a core library and a BOM) from one Gradle project. How do you give each its own artifactId while sharing one group and version?

level: middleimportance: should knowfreq 35%

basics

~10 s

Create two MavenPublications in the same project. Let both inherit groupId and version from project.group/version, but set a distinct artifactId on each so they publish as separate coordinates.

open as a page

A teammate published a library that declares a dependency as 'com.acme:lib:[1.0,2.0)'. A Maven consumer complains the POM is non-deterministic. What went wrong and how do you fix it at the coordinate/versioning layer?

level: seniorimportance: should knowfreq 30%

basics

~20 s

The declared dynamic version range was copied verbatim into the published POM, so Maven re-resolves it and may pick a different version each build. Add versionMapping{} so the POM records the concrete resolved version instead.

open as a page

What problem does versionMapping{} solve in a MavenPublication, and how does it change the generated POM?

level: seniorimportance: should knowfreq 40%

basics

~10 s

versionMapping{} writes the actual resolved dependency versions into the published POM instead of the declared (possibly dynamic or constraint-driven) versions, so consumers using plain Maven see concrete, reproducible versions.

open as a page