skip to content

POM Customization

Filling in the POM metadata Central requires — name, description, url, licenses, developers, scm — plus the withXml escape hatch. Asked of anyone who has published a library publicly.

on this pageshow

questions

5

What is the pom { } block on a MavenPublication, and why might you need to populate it before publishing a library?

level: juniorimportance: must knowfreq 60%

answer

  1. generated pom.xml from MavenPublication
  2. Gradle fills GAV + dependencies only
  3. name/description/url/licenses/developers/scm
  4. Maven Central rejects missing metadata
  5. pom { } configures MavenPom

basics

~10 s

The pom { } block lets you set metadata (name, description, url, licenses, developers, scm) written into the generated pom.xml. You populate it because repositories like Maven Central reject artifacts missing this metadata.

solid answer

~40 s

Every `MavenPublication` produces a `pom.xml`. By default Gradle only fills in the GAV coordinates and dependencies — it does **not** know your project's human-readable name, description, license, authors, or source location. The `pom { }` block on the publication lets you set those: `name`, `description`, `url`, `licenses { license { ... } }`, `developers { developer { ... } }`, and `scm { ... }`. You need it primarily because **Maven Central (Sonatype) validation rejects** POMs that lack a name, description, url, at least one license, a developer, and SCM info. Even for internal repos it's good hygiene so consumers can discover provenance. The block is configured lazily and applies to whichever `MavenPublication` you declare under `publishing { publications { } }`.

code

kotlin · 12 lines
kotlin
publishing {
  publications {
    create<MavenPublication>("maven") {
      from(components["java"])
      pom {
        name.set("My Library")
        description.set("A concise summary")
        url.set("https://example.com/my-lib")
      }
    }
  }
}

go deeper

for a junior

Know that pom { } sets human-readable metadata and that Central requires it.

for a middle

Name the specific required fields and that GAV + deps are automatic.

for a senior

Explain lazy Property configuration and how the POM ties to component variants.

for a principal

Frame POM completeness as a publishing-governance / supply-chain-provenance concern across many modules.

## What a POM is A **POM** (Project Object Model) is the `pom.xml` metadata file Maven-style repositories use to describe a published artifact: its coordinates, dependencies, and descriptive metadata. When you publish with the `maven-publish` plugin, Gradle **generates** a `pom.xml` from your `MavenPublication`. ## What Gradle fills in automatically Out of the box Gradle populates: - **GAV coordinates** — `groupId` (from `project.group`), `artifactId` (the publication name / archivesName), `version` (from `project.version`). - **dependencies** — derived from the variants/configurations the component exposes (e.g. `api`/`implementation` mapped to `compile`/`runtime` scopes). It does **not** infer human metadata — there is nowhere for Gradle to learn your project's display name, description, license, or source URL. ## The pom { } block Inside a `MavenPublication` you configure a `MavenPom` via the `pom { }` block. Common properties: - `name` — display name - `description` — one-line summary - `url` — project home page - `licenses { license { name; url } }` - `developers { developer { id; name; email } }` - `scm { connection; developerConnection; url }` ```kotlin publishing { publications { create<MavenPublication>("maven") { from(components["java"]) pom { name.set("My Library") description.set("A concise summary") url.set("https://example.com/my-lib") licenses { license { name.set("The Apache License, Version 2.0") url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") }} developers { developer { id.set("jdoe"); name.set("Jane Doe"); email.set("[email protected]") }} scm { connection.set("scm:git:git://github.com/me/my-lib.git") developerConnection.set("scm:git:ssh://github.com/me/my-lib.git") url.set("https://github.com/me/my-lib") } } } } } ``` ## Why it matters **Maven Central** (via Sonatype/Central Portal) enforces a metadata checklist and rejects publications missing name, description, url, a license, a developer, and SCM. So even if your code builds fine, publishing fails validation without a populated `pom { }`. The properties are Gradle `Property<T>` types configured lazily — set them with `.set(...)` in Kotlin DSL or `=` in Groovy.

  • Which metadata fields does Maven Central require beyond GAV coordinates?
    name, description, url, at least one license, at least one developer, and scm (connection/developerConnection/url).
  • Does Gradle put dependencies into the POM automatically?
    Yes — they're derived from the component's variants/configurations, mapped to Maven scopes. You don't write them in the pom { } block.

saying these in an interview costs you the question

  • Claiming Gradle auto-generates name/description/license — it doesn't.
  • Thinking pom { } is where you list dependencies.

context

open as a page

What metadata must a POM contain to pass Maven Central validation, and how do you express each field in a Gradle MavenPublication?

level: middleimportance: must knowfreq 55%

basics

~10 s

Central needs name, description, url, at least one license (name + url), at least one developer, and scm connection/developerConnection/url. You set each via the pom { } block on the MavenPublication.

open as a page

How do you generate and inspect the POM Gradle will publish, before actually publishing, and why is that useful?

level: middleimportance: should knowfreq 30%

basics

~10 s

Run the generatePomFileFor<PubName>Publication task; it writes the POM to build/publications/<name>/pom-default.xml. Inspecting it lets you confirm metadata and dependency mapping before a real publish.

open as a page

How would you ensure every module in a large multi-project Gradle build emits a consistent, Central-compliant POM without copy-pasting the pom { } block?

level: seniorimportance: should knowfreq 25%

basics

~10 s

Extract the pom { } configuration into a shared convention plugin (buildSrc or build-logic) applied by every module, parameterizing per-module bits like name/description. Each subproject then gets identical license/developer/scm metadata for free.

open as a page

When would you reach for pom.withXml { } instead of the typed pom { } properties, and what are the trade-offs?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Use pom.withXml { } to edit raw XML the typed DSL can't express — e.g. injecting nodes, tweaking a dependency's scope/exclusions, or adding custom elements. The trade-off is brittle, low-level DOM manipulation that bypasses Gradle's model.

open as a page