skip to content

Publishing to Maven Central

Publishing to Maven Central: staging through the Central Portal or legacy OSSRH, GPG signing, and the POM metadata Central requires. Asked of open-source maintainers and anyone who has cut a public library release.

on this pageshow

explore

questions

6

How do you sign release artifacts for Maven Central, and how is signing typically wired into the build?

level: middleimportance: must knowfreq 48%

answer

  1. maven-gpg-plugin sign goal
  2. binds to verify phase
  3. detached .asc per file
  4. publish public key to keyserver
  5. passphrase via -D or env in CI

basics

~20 s

Use the maven-gpg-plugin. It runs in the verify phase, creates a detached .asc signature for each artifact (jar, sources, javadoc, pom) using your GPG key, and your public key must be on a public keyserver so Sonatype can verify it.

solid answer

~40 s

Central requires every published file to carry a detached PGP/GPG signature (`.asc`). The standard tool is the **maven-gpg-plugin**, whose `sign` goal binds to the `verify` phase and signs all attached artifacts — main jar, `-sources.jar`, `-javadoc.jar`, and the `.pom`. You generate a GPG key pair, publish the **public** key to a keyserver (e.g. keyserver.ubuntu.com) so Sonatype can validate signatures, and keep the private key + passphrase secret. To avoid signing on every developer build, the gpg plugin is placed in a `release` profile. The passphrase is supplied non-interactively in CI via `-Dgpg.passphrase=...` or the gpg-agent/`--pinentry-mode loopback`. Modern setups often use an in-memory key file in CI rather than the local keyring. If a `.asc` is missing or the public key isn't findable, the deployment is rejected.

code

xml · 18 lines
xml
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-gpg-plugin</artifactId>
  <version>3.2.4</version>
  <executions>
    <execution>
      <id>sign-artifacts</id>
      <phase>verify</phase>
      <goals><goal>sign</goal></goals>
      <configuration>
        <gpgArguments>
          <arg>--pinentry-mode</arg>
          <arg>loopback</arg>
        </gpgArguments>
      </configuration>
    </execution>
  </executions>
</plugin>

go deeper

for a junior

Knows artifacts must be GPG-signed and that maven-gpg-plugin does it.

for a middle

Can wire the sign goal into the verify phase and explain the public/private key split.

for a senior

Handles non-interactive CI signing, key rotation/expiry, and profile activation cleanly.

for a principal

Establishes key management/rotation policy and secret handling across the org's release pipelines.

## Why signing Public artifacts must be tamper-evident. Central requires a **detached GPG signature** (`file.asc`) for *every* uploaded file so consumers (and Sonatype) can verify the artifact was produced by the key owner and not altered. ## The key pair - Generate: `gpg --gen-key` (or `--full-generate-key`). - Publish the **public** key so signatures can be verified: `gpg --keyserver keyserver.ubuntu.com --send-keys <KEY_ID>` - Never share the **private** key or passphrase. ## Wiring into the build Use **maven-gpg-plugin**. Its `sign` goal binds to `verify` and signs each attached artifact, emitting `.asc` files alongside them. Put it in a `release` profile so normal `mvn install` builds aren't blocked by signing. ```xml <profile> <id>release</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-gpg-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <id>sign-artifacts</id> <phase>verify</phase> <goals><goal>sign</goal></goals> </execution> </executions> </plugin> </plugins> </build> </profile> ``` ## Passphrase handling - **Local/interactive:** gpg-agent prompts. - **CI/non-interactive:** pass `-Dgpg.passphrase=...` (from a secret) and often configure `<gpgArguments><arg>--pinentry-mode</arg><arg>loopback</arg></gpgArguments>`. The newer plugin also reads `MAVEN_GPG_PASSPHRASE` / `MAVEN_GPG_KEY` env vars. - Store the key id, passphrase, and ASCII-armored private key as CI secrets. ## Verifying yourself ```bash gpg --verify widget-core-1.2.0.jar.asc widget-core-1.2.0.jar ``` ## Failure modes - Public key not on a reachable keyserver → validation fails. - Expired key. - Signing only the jar but not sources/javadoc/pom (the plugin handles all attached artifacts automatically, so disabling attachment breaks it).

  • Why put the gpg plugin in a profile instead of the main build?
    So everyday builds (install/test) don't require the private key or prompt for a passphrase; signing only runs during the explicit release flow.
  • How do you pass the GPG passphrase in CI without a TTY?
    Provide it via -Dgpg.passphrase or the MAVEN_GPG_PASSPHRASE env var and use --pinentry-mode loopback so gpg doesn't try to open an interactive prompt.

saying these in an interview costs you the question

  • Thinking only the main jar needs signing
  • Committing the private key or passphrase to the repo
  • Forgetting to publish the public key so Sonatype can't verify

context

open as a page

What POM metadata is required for a Maven Central release, and why?

level: middleimportance: must knowfreq 50%

basics

~10 s

You need name, description, url, at least one license, an scm block (source control URLs), and at least one developer. These let consumers identify, license-check, and trace the artifact.

open as a page

What is Maven Central, and at a high level what does it take to publish an artifact there?

level: juniorimportance: should knowfreq 45%

basics

~10 s

Maven Central is the default public repository where Maven downloads dependencies. To publish, you need a registered namespace (groupId), full POM metadata, GPG-signed artifacts, and you upload through Sonatype's Central Portal.

open as a page

Can you publish SNAPSHOT versions to Maven Central? Explain SNAPSHOT vs release semantics in this context.

level: middleimportance: should knowfreq 40%

basics

~10 s

No. Maven Central only accepts final release versions. SNAPSHOTs are mutable in-development versions and go to a separate snapshot repository, not Central. Released versions are immutable.

open as a page

Contrast the Central Portal (central-publishing-maven-plugin) with the legacy OSSRH/Nexus staging flow. How does a deploy-to-release work in each?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Legacy OSSRH used a Nexus staging repository: you deploy, a staging repo is created, you close it (runs validations), then release it. The new Central Portal uses central-publishing-maven-plugin to upload a deployment bundle that's validated and published; OSSRH is being retired.

open as a page

Design a reliable, automated CI pipeline that publishes a library to Maven Central on a tagged release. What are the moving parts and failure modes?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

On a version tag, CI builds signed artifacts (jar/sources/javadoc/pom + GPG .asc) with full metadata, then uses central-publishing-maven-plugin to upload and auto-publish. Secrets (GPG key, passphrase, Central token) come from the CI secret store, not the repo.

open as a page