DEV Community

Cover image for Publishing Your Java Library to Maven Central
Selma Guedidi
Selma Guedidi

Posted on

Publishing Your Java Library to Maven Central

Why Maven Central Matters

You've built an amazing Java library. It solves real problems, the code is clean, and you're ready to share it with the world. But there's one crucial step between your local repository and global adoption: publishing to Maven Central.

Maven Central isn't just another package repository: it's the canonical repository for Java and JVM libraries. With over 10 million artifacts and billions of downloads monthly, it's where the entire Java ecosystem comes to find dependencies. When your library is on Maven Central, developers can add it to their projects with a single dependency declaration. No custom repositories, no manual downloads, no friction.

In this guide, I'll walk you through the entire process of publishing to Maven Central, from initial setup to your first release. Whether you're publishing your first library or your tenth, this guide will help you navigate the journey.

Step 1: Create Your Sonatype Account
Maven Central is operated by Sonatype, and they've recently modernized the onboarding process. You'll need to create an account on their new platform.

  1. Go to https://central.sonatype.com
  2. Click "Sign up" (you can use GitHub, Google, or email)
  3. Verify your email address if using email registration

Step 2: Claim Your Namespace

Namespace ownership is fundamental to publishing on Maven Central. Your namespace (groupId) serves as the unique identifier for all your published artifacts, and you must demonstrate legitimate ownership before you can publish. The Central Portal offers two primary verification methods, each suited to different use cases.

Method 1: DNS-Based Verification (For Domain Owners)

If you own or maintain a registered domain name, you can leverage the Domain Name System in reversed format for your namespace. This approach mirrors Java's package naming convention and provides the most flexibility for organizational publishing.

How It Works:

The namespace uses your domain name in reverse order, allowing you to create as many subsections as needed for organizational purposes.

Examples:

  • Domain: example.com → Namespace: com.example
  • Domain: subdomain.example.com → Namespace: com.example
  • Domain: my-domain.com → Namespace: com.my-domain

Once verified, you can utilize any groupId starting with your reversed domain and extend it with additional subsections:

  • com.example.domain
  • com.example.test
  • com.example.utilities.logging

Important Considerations:

Exact Reversal: The groupId must reverse the domain name exactly as it appears, preserving hyphens and special characters even if they would produce invalid Java package names. This is acceptable and expected, your Java package names need not match your groupId.
Ownership Requirement: You must have control over the domain to add DNS verification records.

Verification Process:

  1. Navigate to "Namespaces" in the left sidebar
  2. Click "Add Namespace"
  3. Enter your reversed domain namespace (e.g., com.example)
  4. Select "DNS Verification" as your verification method
  5. Copy the provided TXT record from the portal
  6. Add this TXT record to your domain's DNS configuration
  7. Return to the portal and click "Verify Namespace"
  8. Verification typically completes within minutes once DNS propagates

Method 2: Code Hosting Service Verification (Personal Namespace)

For individual developers and open-source projects hosted on popular code hosting platforms, Maven Central provides a streamlined verification process using your platform identity. This method is ideal for personal libraries and projects without a custom domain.

Supported Platforms:

Code Hosting Service Username Pattern Example Namespace
GitHub myusername io.github.myusername
GitLab myusername io.gitlab.myusername
Gitee myusername io.gitee.myusername
Bitbucket myusername io.bitbucket.myusername

How It Works:

The namespace format follows the pattern io.{platform}.{username}, where the username matches your account on the respective platform. This creates a globally unique namespace tied to your platform identity.

Verification Process:

  1. Navigate to "Namespaces"
  2. Click "Add Namespace"
  3. Enter your platform-based namespace (e.g., io.github.myusername)
  4. Select your code hosting service as the verification method
  5. The portal will prompt you to create a temporary public repository with a specific verification name
  6. Create the repository on your platform with the exact name provided
  7. Return to the portal and click "Verify Namespace"
  8. Verification is typically instant once the repository is detected

Step 3: Generate GPG Keys

Maven Central enforces a strict security requirement: all published artifacts must be cryptographically signed using GPG (GNU Privacy Guard). This digital signature ensures artifact integrity and authenticity, protecting the entire Java ecosystem from tampering and unauthorized modifications.

3.1 Installing GPG

Before generating keys, you need to ensure GPG is installed on your system.

For macOS

Using Homebrew (recommended):

brew install gnupg
Enter fullscreen mode Exit fullscreen mode

Using MacPorts:

sudo port install gnupg2
Enter fullscreen mode Exit fullscreen mode

Verify installation:

gpg --version
Enter fullscreen mode Exit fullscreen mode

For Linux

Debian/Ubuntu:

sudo apt-get update
sudo apt-get install gnupg
Enter fullscreen mode Exit fullscreen mode

Fedora/RHEL/CentOS:

sudo dnf install gnupg2
Enter fullscreen mode Exit fullscreen mode

Arch Linux:

sudo pacman -S gnupg
Enter fullscreen mode Exit fullscreen mode

Verify installation:

gpg --version
Enter fullscreen mode Exit fullscreen mode

For Windows

Option 1: Using Gpg4win (Recommended)

  1. Download Gpg4win from https://gpg4win.org/download.html
  2. Run the installer and follow the installation wizard
  3. Add GPG to your PATH if not done automatically

Option 2: Using Chocolatey

choco install gnupg
Enter fullscreen mode Exit fullscreen mode

Option 3: Using Windows Subsystem for Linux (WSL)

sudo apt-get install gnupg
Enter fullscreen mode Exit fullscreen mode

Verify installation (in Command Prompt or PowerShell):

gpg --version
Enter fullscreen mode Exit fullscreen mode

3.2 Generating Your Key Pair

Once GPG is installed, generate a new key pair for signing your artifacts:

gpg --gen-key
Enter fullscreen mode Exit fullscreen mode

Follow the interactive prompts to configure your key:

  • Key type: Choose RSA and RSA (default)
  • Key size: Use 2048 bits or higher (4096 recommended)
  • Expiration: Set to 2-3 years (recommended) or no expiration
  • Real name: Your name or organization name
  • Email address: A professional email you control
  • Comment: Optional (e.g., "Maven Central Signing Key")
  • Passphrase: Create a strong passphrase

Critical: Your passphrase will be required for every release. Store it securely in a password manager—you cannot recover it if lost, and you'll need it throughout your publishing workflow.

Listing Your Keys

After generation, verify your keys:

gpg --list-keys
Enter fullscreen mode Exit fullscreen mode

Output will look like:

pub   rsa4096 2025-10-05 [SC] [expires: 2027-10-05]
      1234567890ABCDEF1234567890ABCDEF12345678
uid           [ultimate] John Doe (Maven Central Signing Key) <john.doe@example.com>
sub   rsa4096 2025-10-05 [E] [expires: 2027-10-05]
Enter fullscreen mode Exit fullscreen mode

The long hexadecimal string is your key ID. You can also use the last 8 characters as a short key ID.

3.3 Publishing Your Public Key

For Maven Central to verify your signatures, your public key must be published to a public key server:

# Using the full key ID
gpg --keyserver keys.openpgp.org --send-keys 1234567890ABCDEF1234567890ABCDEF12345678

# Or using the short key ID (last 8 characters)
gpg --keyserver keys.openpgp.org --send-keys 12345678
Enter fullscreen mode Exit fullscreen mode

Note: It may take a few minutes for your key to propagate across key server networks.

Verifying Key Publication

Confirm your key is publicly accessible:

gpg --keyserver keys.openpgp.org --recv-keys YOUR_KEY_ID
Enter fullscreen mode Exit fullscreen mode

If successful, you'll see:

gpg: key YOUR_KEY_ID: "John Doe (Maven Central Signing Key) <john.doe@example.com>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1
Enter fullscreen mode Exit fullscreen mode

Next Steps

With your GPG keys generated, published, and backed up, you're ready to configure your build tool to automatically sign artifacts during the publishing process. Your key ID and passphrase will be required in the build configuration covered in Step 4.

Step 4: Configure Your Build Tool

Configuring Maven for publishing to Maven Central requires understanding two distinct deployment workflows: release versions and snapshot versions. Each serves a different purpose in the development lifecycle and has different requirements.

Understanding Release vs Snapshot Versions

Release Versions (e.g., 1.0.0, 2.3.1, 1.5.0-beta1):

  • Immutable and permanent once published
  • Require complete metadata, including developers, SCM, and license information
  • Undergo full validation before publication
  • Intended for production use and stable APIs
  • Cannot be overwritten or deleted after publication

Snapshot Versions (e.g., 1.0.0-SNAPSHOT, 2.3.1-SNAPSHOT):

  • Mutable and can be republished with the same version
  • Require minimal metadata validation
  • Used for development, testing, and continuous integration
  • Not indexed in Maven Central search
  • Must be explicitly enabled in your namespace configuration

Generating Authentication Tokens

Before configuring your build, you need to generate authentication tokens from the Central Portal:

  1. Log in to https://central.sonatype.com
  2. Click on your account name in the top right corner
  3. Select "View User Tokens" from the dropdown
  4. Click "Generate User Token"
  5. The portal will display your username and password token
  6. Save these immediately—the password token is only shown once

Important: These tokens are not your Sonatype login credentials. They are specifically generated for programmatic publishing and should be treated as API keys.

Enabling Snapshot Publishing (Optional)

If you plan to publish snapshot versions, you must enable this feature in your namespace:

  1. Log in to https://central.sonatype.com
  2. Navigate to "Namespaces"
  3. Select your verified namespace
  4. Click on its "dropdown menu"
  5. Click on "Enable Snapshots"
  6. Save the configuration

Without this setting enabled, snapshot deployments will fail with an authorization error.

Namespaces with snapshots enabled


Configuration for Release Versions

Release versions require comprehensive metadata and validation. This configuration ensures your artifacts meet all Maven Central requirements.

Maven POM Configuration

Add the following to your pom.xml:

<project>
    <groupId>io.github.yourusername</groupId>
    <artifactId>your-library</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <name>Your Library Name</name>
    <description>A comprehensive description of your library's purpose and functionality</description>
    <url>https://github.com/yourusername/your-library</url>

    <licenses>
        <license>
            <name>Apache License, Version 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
            <distribution>repo</distribution>
        </license>
    </licenses>

    <developers>
        <developer>
            <id>yourusername</id>
            <name>Your Full Name</name>
            <email>your.email@example.com</email>
            <organization>Your Organization</organization>
            <organizationUrl>https://yoursite.com</organizationUrl>
        </developer>
    </developers>

    <scm>
        <connection>scm:git:git://github.com/yourusername/your-library.git</connection>
        <developerConnection>scm:git:ssh://github.com:yourusername/your-library.git</developerConnection>
        <url>https://github.com/yourusername/your-library/tree/main</url>
        <tag>HEAD</tag>
    </scm>

    <build>
        <plugins>
            <!-- Central Publishing Plugin -->
            <plugin>
                <groupId>org.sonatype.central</groupId>
                <artifactId>central-publishing-maven-plugin</artifactId>
                <version>0.9.0</version>
                <extensions>true</extensions>
                <configuration>
                    <publishingServerId>central</publishingServerId>
                    <autoPublish>true</autoPublish>
                    <waitUntil>published</waitUntil>
                </configuration>
            </plugin>

            <!-- GPG Signing Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-gpg-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <id>sign-artifacts</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>sign</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!-- Retrieves passphrase from settings.xml -->
                    <passphraseServerId>gpg.passphrase</passphraseServerId>
                    <!-- Required for gpg2 to avoid GUI prompts -->
                    <gpgArguments>
                        <arg>--pinentry-mode</arg>
                        <arg>loopback</arg>
                    </gpgArguments>
                    <!-- Ensure correct GPG binary is used -->
                    <executable>gpg</executable>
                </configuration>
            </plugin>

            <!-- Source Attachment Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>3.3.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <!-- Javadoc Generation Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>3.6.3</version>
                <executions>
                    <execution>
                        <id>attach-javadocs</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!-- Optional: Configure Javadoc strictness -->
                    <doclint>none</doclint>
                    <quiet>true</quiet>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
Enter fullscreen mode Exit fullscreen mode

Plugin Explanations

Central Publishing Maven Plugin

<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.9.0</version>
Enter fullscreen mode Exit fullscreen mode

This is the modern publishing plugin that replaces the legacy Nexus staging plugin. It handles the entire deployment workflow to Maven Central.

Key Configuration Options:

  • publishingServerId: References the server credentials in settings.xml (must be central)
  • autoPublish: When true, automatically publishes after successful validation. When false, requires manual approval in the Central Portal
  • waitUntil: Controls deployment behavior
    • uploaded: Waits until artifacts are uploaded
    • validated: Waits until validation completes
    • published: Waits until artifacts are fully published to Maven Central (recommended)

Maven GPG Plugin

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.1.0</version>
Enter fullscreen mode Exit fullscreen mode

Signs all project artifacts (JAR, sources, javadoc, POM) with your GPG key during the verify phase.

Key Configuration Options:

  • passphraseServerId: References the GPG passphrase stored in settings.xml, avoiding hardcoded credentials
  • gpgArguments: Configures GPG behavior
    • --pinentry-mode loopback: Essential for non-interactive environments (CI/CD) and gpg2, prevents GUI password prompts
  • executable: Specifies the GPG binary path. Use gpg2 if you have both versions installed

Maven Source Plugin

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
Enter fullscreen mode Exit fullscreen mode

Generates a JAR file containing your source code. Maven Central mandates source JARs for all releases.

Key Configuration:

  • jar-no-fork: Creates the source JAR without forking a new Maven lifecycle, improving build performance

Maven Javadoc Plugin

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
Enter fullscreen mode Exit fullscreen mode

Generates comprehensive API documentation and packages it as a JAR. Maven Central requires Javadoc JARs for all releases.

Optional Configuration:

  • doclint: Set to none to disable strict Javadoc validation (useful if you have legacy code with incomplete docs)
  • quiet: Reduces console output during generation

Maven Settings Configuration

Add the following to your ~/.m2/settings.xml:

<settings>
    <servers>
        <!-- Central Portal Authentication -->
        <server>
            <id>central</id>
            <username>YOUR_GENERATED_TOKEN_USERNAME</username>
            <password>YOUR_GENERATED_TOKEN_PASSWORD</password>
        </server>

        <!-- GPG Passphrase -->
        <server>
            <id>gpg.passphrase</id>
            <passphrase>YOUR_GPG_PASSPHRASE</passphrase>
        </server>
    </servers>
</settings>
Enter fullscreen mode Exit fullscreen mode

Deploying a Release

Execute the deployment with a single command:

mvn clean deploy
Enter fullscreen mode Exit fullscreen mode

This command will:

  1. Clean previous build artifacts
  2. Compile your code
  3. Run tests
  4. Generate source and Javadoc JARs
  5. Sign all artifacts with GPG
  6. Upload to Maven Central
  7. Validate the deployment
  8. Automatically publish (if autoPublish is true)

Verification: Monitor the deployment at https://central.sonatype.com/publishing/deployments


Configuration for Snapshot Versions

Snapshot versions are designed for rapid iteration during development. They have relaxed validation requirements and can be republished multiple times.

Maven POM Configuration for Snapshots

Snapshots require minimal metadata compared to releases:

<project>
    <groupId>io.github.yourusername</groupId>
    <artifactId>your-library</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <!-- Minimal required metadata for snapshots -->
    <name>Your Library Name</name>
    <description>Development snapshot of Your Library</description>
    <url>https://github.com/yourusername/your-library</url>

    <build>
        <plugins>
            <!-- Central Publishing Plugin (same as releases) -->
            <plugin>
                <groupId>org.sonatype.central</groupId>
                <artifactId>central-publishing-maven-plugin</artifactId>
                <version>0.9.0</version>
                <extensions>true</extensions>
                <configuration>
                    <publishingServerId>central</publishingServerId>
                    <autoPublish>true</autoPublish>
                </configuration>
            </plugin>

            <!-- GPG Signing (same as releases) -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-gpg-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <id>sign-artifacts</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>sign</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <passphraseServerId>gpg.passphrase</passphraseServerId>
                    <gpgArguments>
                        <arg>--pinentry-mode</arg>
                        <arg>loopback</arg>
                    </gpgArguments>
                    <executable>gpg</executable>
                </configuration>
            </plugin>

            <!-- Source and Javadoc plugins are optional for snapshots -->
            <!-- Include them if you want consistent artifact structure -->
        </plugins>
    </build>
</project>
Enter fullscreen mode Exit fullscreen mode

Key Differences for Snapshots

Relaxed Requirements:

  • No <developers> section required
  • No <scm> section required
  • No <licenses> section required (though recommended)
  • Source and Javadoc JARs are optional

Version Format:

  • Must end with -SNAPSHOT (e.g., 1.0.0-SNAPSHOT, 2.1.0-SNAPSHOT)
  • Can be republished multiple times without changing the version number

Publication Behavior:

  • Not indexed in Maven Central search
  • Available immediately after upload
  • Stored in a separate snapshot repository
  • Automatically cleaned up after a retention period

Deploying a Snapshot

Deploy snapshots using the same command:

mvn clean deploy
Enter fullscreen mode Exit fullscreen mode

Maven automatically detects the -SNAPSHOT suffix and routes the deployment to the snapshot repository.

Consuming Published Snapshots

To use snapshots published by others (or your own), configure your project's pom.xml or settings.xml:

In Your Project's POM

<repositories>
    <repository>
        <id>central-portal-snapshots</id>
        <name>Central Portal Snapshots</name>
        <url>https://central.sonatype.com/repository/maven-snapshots/</url>
        <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
        </snapshots>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
</repositories>
Enter fullscreen mode Exit fullscreen mode

In Your Settings.xml (Global Configuration)

<settings>
    <profiles>
        <profile>
            <id>central-snapshots</id>
            <repositories>
                <repository>
                    <id>central-portal-snapshots</id>
                    <name>Central Portal Snapshots</name>
                    <url>https://central.sonatype.com/repository/maven-snapshots/</url>
                    <snapshots>
                        <enabled>true</enabled>
                        <updatePolicy>always</updatePolicy>
                    </snapshots>
                </repository>
            </repositories>
        </profile>
    </profiles>

    <activeProfiles>
        <activeProfile>central-snapshots</activeProfile>
    </activeProfiles>
</settings>
Enter fullscreen mode Exit fullscreen mode

Configuration Options:

  • updatePolicy: Controls how often Maven checks for snapshot updates
    • always: Check on every build (recommended for active development)
    • daily: Check once per day (default)
    • interval:X: Check every X minutes
    • never: Never check for updates

Additional Resources

For more detailed information and the latest updates, refer to the official Sonatype documentation:

The official documentation provides comprehensive coverage of edge cases, advanced configurations, and troubleshooting scenarios that may not be covered in this guide.

Note: Sonatype recently migrated from the old JIRA-based system to the new Central Portal at central.sonatype.com. If you find older tutorials mentioning JIRA tickets and issues.sonatype.org, that process is now deprecated. This guide reflects the current, streamlined process.

Questions or issues? Drop a comment below, and I'll do my best to help!

Top comments (0)