skip to content

Sonatype and Maven Central

Publishing to Central Portal or OSSRH staging: namespace verification and the bundle requirements for sources, javadoc, and signatures. Asked of anyone who has released to Maven Central from a Gradle build.

on this pageshow

questions

5

What artifacts must a Maven Central release bundle contain beyond the main JAR, and why does Central reject a publication that is missing them?

level: juniorimportance: must knowfreq 62%

answer

  1. main + sources + javadoc + POM
  2. .asc signature per file
  3. withSourcesJar / withJavadocJar
  4. POM needs license/scm/developers
  5. validation is server-side

basics

~10 s

Each release must include the main JAR plus a sources JAR, a javadoc JAR, a POM, and PGP/GPG signatures (.asc) for every file. Central validation rejects bundles missing any of these.

solid answer

~40 s

Maven Central enforces a minimum bundle for every released coordinate: the primary artifact (usually the JAR), a `-sources.jar`, a `-javadoc.jar`, a complete POM (with name, description, URL, license, developers, SCM), and a detached PGP signature (`.asc`) for **each** of those files plus the POM. The sources/javadoc requirement exists so consumers can read code and docs in their IDE; signatures let anyone verify provenance against the publisher's public key. In Gradle you produce the extra JARs with `java { withSourcesJar(); withJavadocJar() }` and sign everything with the `signing` plugin applied to the `maven-publish` publication. Central's validation (Portal or legacy OSSRH) runs these checks server-side and fails the staging deployment if anything is absent or a signature does not verify.

code

kotlin · 8 lines
kotlin
java {
    withSourcesJar()
    withJavadocJar()
}

signing {
    sign(publishing.publications["maven"])
}

go deeper

for a junior

List the four artifact kinds plus signatures and note Central rejects incomplete bundles.

for a middle

Show the exact Gradle wiring (withSourcesJar/withJavadocJar + signing) and name the POM fields validated.

for a senior

Explain why immutability drives the contract and how Kotlin projects satisfy javadoc via Dokka.

for a principal

Frame it as a supply-chain/provenance guarantee and discuss enforcing the bundle contract across many modules via convention plugins.

## Why Maven Central has a bundle contract Maven Central is the default public repository for the JVM ecosystem. Because anything published there is **immutable and globally consumable forever**, Sonatype enforces a strict quality and provenance contract before a coordinate (`group:artifact:version`) goes live. A 'bundle' is the complete set of files uploaded for one version. ## The required files For a typical Java/Kotlin library version Central requires: - **Main artifact** — the `.jar` (or `.aar`, `.war`, etc.). - **Sources JAR** — `artifact-version-sources.jar`, so consumers can step into your code. - **Javadoc JAR** — `artifact-version-javadoc.jar`. (For Kotlin you can publish a stub/Dokka-generated jar; an empty javadoc jar with a placeholder is also commonly accepted, but a real one is better.) - **POM** — must carry `name`, `description`, `url`, at least one `license`, `developers`, and `scm` blocks. Central validates these fields. - **PGP signatures** — a detached ASCII-armored `.asc` for **every** file above, including the POM and the checksums. The public key must be discoverable on a public keyserver. ## Producing them in Gradle With `maven-publish`, `signing`, and the `java` plugin: ```kotlin plugins { `java-library` `maven-publish` signing } java { withSourcesJar() withJavadocJar() } publishing { publications { create<MavenPublication>("maven") { from(components["java"]) pom { name.set("my-lib") description.set("A useful library") url.set("https://github.com/me/my-lib") licenses { license { name.set("Apache-2.0") } } developers { developer { id.set("me"); name.set("Me") } } scm { url.set("https://github.com/me/my-lib") } } } } } signing { sign(publishing.publications["maven"]) } ``` `withSourcesJar()`/`withJavadocJar()` register `sourcesJar`/`javadocJar` tasks and wire them into the `java` component, so `from(components["java"])` automatically attaches them to the publication. `sign(...)` produces the `.asc` files at publish time. ## What validation checks When the bundle reaches Central (via the Central Portal upload or the legacy OSSRH staging repository), server-side validation verifies: presence of sources + javadoc, POM completeness, a valid signature on each file, and that the signing public key resolves on a keyserver. Any failure leaves the deployment in a failed/dropped state and it never goes public.

  • Kotlin libraries have no real Javadoc — how do people satisfy the javadoc-JAR requirement?
    Generate one with the Dokka plugin's javadoc-format task and attach it as the javadoc jar, or attach a minimal placeholder javadoc jar. Central requires the artifact to exist; it doesn't deeply inspect its contents.
  • Which POM fields does Central specifically validate?
    name, description, url, at least one license, developers, and scm. Missing any of these fails validation.

saying these in an interview costs you the question

  • Saying only the main JAR is needed for Central.
  • Claiming signatures are optional for public releases.
  • Confusing the javadoc/sources requirement with snapshot publishing (snapshots are more lenient — but that's a sibling topic).

context

open as a page

How does Sonatype namespace (groupId) verification work for Maven Central, and what must you do before you can publish under a given group?

level: middleimportance: must knowfreq 55%

basics

~20 s

Your groupId is a namespace you must prove you control. For a domain-based group you add a TXT DNS record; for a code-host group (io.github.user) you verify via the matching account. Central won't accept artifacts until the namespace is verified.

open as a page

Why does Maven Central require PGP/GPG signatures on published artifacts, and how do you wire the Gradle signing plugin to satisfy it (including on CI)?

level: seniorimportance: must knowfreq 45%

basics

~20 s

Signatures let anyone verify an artifact came from the real publisher and wasn't tampered with. In Gradle you apply the signing plugin and sign(publication); the public key must be on a keyserver. On CI you provide the key/passphrase via the in-memory signing keys.

open as a page

Compare the Central Portal and the legacy OSSRH staging endpoints. What URLs/targets does each use and how does a Gradle build point at them?

level: middleimportance: should knowfreq 40%

basics

~10 s

Legacy OSSRH used per-account Nexus staging URLs like s01.oss.sonatype.org/service/local/staging/deploy/maven2. The new Central Portal uploads a bundle to central.sonatype.com via its Publisher API. New accounts use the Portal; OSSRH is being retired.

open as a page

Walk through what happens to a release after Gradle uploads it: the staging lifecycle on Sonatype before it appears on Maven Central.

level: seniorimportance: should knowfreq 35%

basics

~20 s

After upload, the bundle lands in a staging area where Sonatype validates the artifacts (signatures, sources/javadoc, POM). If valid you release/publish it; it then syncs to the public Central index and mirrors within a short time.

open as a page