Publishing build artifacts on Maven Central
December 11, 2025 ยท View on GitHub
This document provides information on how to configure your Java SDK project to successfully publish build artifacts (jars, pom.xml files, etc.) on the Maven Central public maven artifact repository.
Table of Contents
- Overview
- 1: Register a new Sonatype account
- 2: Using the com.ibm.cloud maven group id
- 3: Create a public/private key pair for signing artifacts
- 4: Modify your Java SDK project to publish artifacts on Maven Central
- 5: Java SDK Build lifecycle overview
- Appendix:
- References:
Overview
This document will assist you in configurating your Java SDK project to publish artifacts on Maven Central.
These Sonatype documents should be considered to be the authoritative source of information regarding the proper steps to be followed for publishing artifacts on Maven Central:
- Getting Started - this describes the process to publish artifacts using the "legacy" (OSSRH) process.
- Register to publish via the Central Portal.
Note that the previous publishing process via the OSSRH service (aka Sonatype's "legacy" process) has reached end of life, so now all IBM Cloud Java SDK projects must use the new process.
The intent of this document is to provide specific instructions to guide IBM Cloud Java SDK maintainers in performing the steps outlined in aforementioned guide.
1: Register a new Sonatype account
It is highly recommended that you use a functional ID to publish artifacts to Maven Central. If you do not already have a Sonatype account, you'll need to create one before proceeding.
To register a new account, follow the instructions here.
After you have established your Sonatype account, follow the instructions
here to generate a user token suitable for publishing.
After generating the token, be sure to save the username and password
values associated with your token in a safe place (we'll use them later).
2: Using the com.ibm.cloud maven group id
You'll be publishing your artifacts using the already-existing maven group id com.ibm.cloud.
Therefore, you do not need to create a new namespace as mentioned in the registration documentation.
Using the existing com.ibm.cloud maven group id provides some consistency for IBM Cloud customers
wishing to use the artifacts produced by various Java SDK projects (i.e. IBM Cloud services).
A Java SDK project's main artifact (the "parent" project) should have an artifact id that represents
the service category (e.g. platform-services), and each module within the project should have an
artifact id that reflects the name of the service contained in that module (e.g. resource-controller,
global-catalog, configuration-governance, etc.).
An artifact's group id, artifact id, and version form the maven coordinates needed by users to
define a dependency on the artifact (e.g. com.ibm.cloud:global-catalog:1.3.1).
Make sure the coordinates of each of your Java SDK project's artifacts are properly documented in your
project's README.md file.
2.1: Request permissions to publish artifacts in com.ibm.cloud group
Follow the instructions here
to request permissions to publish artifacts using the com.ibm.cloud maven group id.
Specifically, you'll need to send an email to the "Central Support" team and provide the following info
- request type - add "publish" permissions for the specified user
- the username (the username associated with the account you created above)
- the namespace (maven group id): com.ibm.cloud
The request will be routed to the person that manages permissions for the
com.ibmnamespace (an IBMer).
3: Create a public/private key pair for signing artifacts
One of the requirements for publishing artifacts on Maven Central is that each file (jar, pom.xml, etc.) must be signed, and this requires the use of a public/private key pair.
Detailed instructions on how to create a new signing key can be found here.
In order to automatically sign artifacts during your automated CI builds, you'll need to export your key, encrypt it, and then add the encrypted file to your SDK project's git repository so that it can be used during your automated builds. See the instructions below on how to do this. This process depends on the CI/CD solution that you'll use in the project.
3.1: Generate a new public/private key pair
Use the detailed instructions to generate a new key pair:
gpg --gen-key
Use RSA for the kind and 2048-bit as the size of the key.
Be sure to specify a non-trivial passphrase and save it somewhere secure
(add it to your password manager, etc.). Omitting the passphrase makes it easier to forge artifact
signatures.
This command creates the new key within your local keystore managed by the gpg command
(called $HOME/.gnupg/pubring.kbx or something similar).
3.2: List keys
To list your keys:
gpg --list-keys
Example:
$ gpg --list-keys
/home/padams/.gnupg/pubring.kbx
-------------------------------
pub rsa2048 2020-11-22 [SC] [expires: 2022-11-22]
B265BB91D80124E463C63119EC4158B05D352E09
uid [ultimate] Phillip C. Adams <phil_adams@us.ibm.com>
sub rsa2048 2020-11-22 [E] [expires: 2022-11-22]
3.3: Publish your public key
In order to publish artifacts on Maven Central, you will need to publish your public key on a key server so that Sonatype can verify your artifacts before releasing them to Maven Central.
3.3.1 Via gpg command line
One way to publish your public key is to use the gpg command like this:
$ gpg --keyserver keys.openpgp.org --send-keys B265BB91D80124E463C63119EC4158B05D352E09
gpg: sending key EC4158B05D352E09 to hkp://keys.openpgp.org
Be sure to use your key's id in place of B265BB91D80124E463C63119EC4158B05D352E09 :).
3.3.2 Via key server web interface
Sometimes, the gpg command line method mentioned above will fail with a "connection timeout" or other networking-related error. Alternatively, you can publish your public key via the key server's web interface. To do this, you first need to export your public key like this:
$ gpg --armor --export B265BB91D80124E463C63119EC4158B05D352E09 > mykey.pub
Be sure to use your key's id in place of B265BB91D80124E463C63119EC4158B05D352E09 :).
Next, open the keyserver web interface then click the "upload"
link below the search entry field.
Next, click "Browse" and select the file to which you exported your public key
in the previous step (e.g. mykey.pub), then click the "Upload" button.
3.3.3 Verify your key was published
Next, you can verify that your key was published.
Open that page and enter the key id (either the full key id or the last 16 characters... e.g.
B265BB91D80124E463C63119EC4158B05D352E09 or EC4158B05D352E09 from the example above, but be sure
to use your own key id), then click Search.
Your public key should be returned as a result of the search.
Publishing your public key also allows users of your artifacts to verify them with the gpg command:
$ gpg --verify <jar_filename>.asc
3.4: Export your key
After following the steps above, you should have a new signing key (a public/private key pair) within your local keystore. This key will need to be exported, encrypted, and then added to your project's git repository so that your CI/CD build can import the key into the build agent's local keystore to allow the maven build running on that agent to automatically sign your artifacts with your signing key.
So, while we're dealing with the gpg-related steps here, we might as well export it now:
gpg --export-secret-key -a B265BB91D80124E463C63119EC4158B05D352E09 > signing.key
Of course, replace B265BB91D80124E463C63119EC4158B05D352E09 with your key's id
(found in the output of the gpg --list-keys command above).
You should now have a text file named signing.key that looks like this:
-----BEGIN PGP PRIVATE KEY BLOCK-----
<contents of private key>
-----END PGP PRIVATE KEY BLOCK-----
Next, we'll update your Java SDK project so that it can automatically sign and publish your build artifacts.
4: Modify your Java SDK project to publish artifacts on Maven Central
In this section, you will be making updates to your Java SDK project, so be sure to create a new feature branch from your current "master" (or "main") branch.
Note: If you created a new Java SDK project from the Java SDK Template repository on or after 02/06/2021, then your project should already have the changes outlined in this section of the document. This section is intended mainly for those that have created their project from an earlier version of the template repository and need to update their project to remove the bintray publishing step and replace it with a maven central publishing step.
4.1: Copy files from the Java SDK template repository
Copy the following files from the
Java SDK Template repository
into the build directory of your Java SDK project:
build/generateJavadocIndex.shbuild/publishJavadoc.shbuild/setMavenVersion.shbuild/setupSigning.sh
If you'll use Travis instead of GitHub Actions, add the following files too:
- publishJavadoc.sh (Travis version)
build/.travis.settings.xml(Only if you are about to use Travis)
Next, within your Java SDK project, modify the build/generateJavadocIndex.sh file to reflect
your Java SDK project (i.e. the title, h1 heading, <service-category>, and <github-repo-url>).
4.2: Update your .travis.xml file
Note: this section is only applicable to Travis. If you'll use other CI/CD solution - like GitHub Actions -, skip this and move to the next one.
Next, replace your project's .travis.yml file with the contents of
.travis.yml.sdk from the Java SDK Template repository.
If you have project-specific settings in your .travis.yml file, be sure to back up the file first,
then copy any project-specific settings to your new .travis.yml file.
You should end up with a new .travis.yml file in the root directory of your project.
Within the .travis.yml file, remove the comments from the stages and jobs sections
(there are instructions inside the file).
4.3: Add your signing key to your git repository.
Note: this section is only applicable to Travis. If you'll use other CI/CD solution - like GitHub Actions -, skip this and move to the next one.
In this step, you'll encrypt the signing.key file that you previously
exported and add it to your git repo within the build directory.
Detailed instructions on how to encrypt a file and add it to your repository can be found here, so the instructions below will be kept brief:
$ cd <project-root>
# Copy your signing.key file to your project's "build" directory.
# Replace "<dir>" with the name of the directory containing the signing.key file
# that you exported previously.
$ cp <dir>/signing.key ./build
$ travis login --github-token <your-public-github-token> --com
$ travis encrypt-file build/signing.key build/signing.key.enc --com
The travis encrypt-file command will display an openssl command as part of its output.
Here is an example:
openssl aes-256-cbc -K $encrypted_4b7d603e7466_key -iv $encrypted_4b7d603e7466_iv -in build/signing.key.enc -out build/signing.key -d
Next, modify the openssl command found inside the build/setupSigning.sh script to reflect the
names of the environment variables from the openssl command displayed by the
travis encrypt-file command (or just copy the entire openssl command and replace the one in the script.
In the example above, the environment variable names are
$encrypted_4b7d603e7466_key and $encrypted_4b7d603e7466_iv.
The travis encrypt-file command added these environment variables to your project's Travis build settings.
Finally, remove the build/signing.key file (remove only the plain-text file and
keep the build/signing.key.enc file):
$ rm build/signing.key
4.4: Update the parent pom.xml
In this step, you'll modify your Java SDK project's parent pom.xml file (in the project root directory) to add the necessary configuration to allow your project to sign and publish your build artifacts. As a reminder, if you created your project from a recent version of the template repository, you likely already have these changes reflected in your parent pom.xml.
The most straightforward way to perform this step might be to "diff" your pom.xml file with the parent pom.xml in the Java SDK Template repository and apply the necessary changes, while retaining your project-specific settings. However, I'll attempt to summarize the changes here:
- In the
<properties>section, remove the<bintray-plugin-version>property, then add these properties:
<central-publish-plugin-version>0.8.0</central-publish-plugin-version>
<maven-gpg-plugin-version>3.1.0</maven-gpg-plugin-version>
-
Also in the
<properties>section, remove these properties:<bintray.org><bintray.repo><bintray.package.url>
-
Within the
<modules>section, make sure that yourexamplesmodule is listed last, after thecoverage-reportsmodule. -
In the
<repositories>section, remove the<repository>entry with idjcenter(if present). -
In the
<build>/<pluginManagement>/<plugins>section, remove the<plugin>entry for "bintray-maven-plugin", and add the following:
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>${central-publish-plugin-version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin-version}</version>
</plugin>
-
In the
<build>/<plugins>section, remove the<plugin>entry for "bintray-maven-plugin". -
After the
<developers>section (i.e. immediately before the file's closing</project>line), add the following<profiles>section:
<profiles>
<!-- "central" is used to deploy artifacts on maven central -->
<profile>
<id>central</id>
<!-- For this profile, we'll get dependencies from maven central -->
<repositories></repositories>
<distributionManagement>
<snapshotRepository>
<!-- We don't deploy snapshot releases -->
</snapshotRepository>
<repository>
<!-- This is where the nexus staging plugin will publish artifacts -->
<id>central</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
<configuration>
<gpgArguments>
<gpgArgument>--batch</gpgArgument>
<gpgArgument>--yes</gpgArgument>
<gpgArgument>--no-tty</gpgArgument>
</gpgArguments>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<!-- Configure the gpg plugin to use the env vars defined in the Travis build settings -->
<gpg.keyname>${env.GPG_KEYNAME}</gpg.keyname>
<gpg.passphrase>${env.GPG_PASSPHRASE}</gpg.passphrase>
</properties>
</profile>
</profiles>
Note: if you already have a <profiles> section, then simply add the <profile> entry with id "central" to it.
4.5: Update the coverage-reports module pom.xml
In this step, you'll modify the modules/coverage-reports/pom.xml file to prevent the coverage-reports
module from being published on maven central.
- Add this
<properties>section immediately before the<dependencies>section:
<properties>
<!-- There is no need to publish this module's artifacts on maven central -->
<maven.deploy.skip>true</maven.deploy.skip>
<skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo>
</properties>
- In the
<build>/<plugins>section, remove the<plugin>entry with id "bintray-maven-plugin".
4.6: Update your build settings
4.6.1: For GitHub Actions
For setting up GitHub Actions, refer to the Using GitHub Actions instead of Travis-CI for your project's CI/CD part of this document while you are reading the instructions below.
4.6.2: For Travis
Open the Travis build settings page for your SDK project
(i.e. https://travis-ci.com/github/IBM/<repo-name>),
and add the following environment variables to your build configuration:
-
GH_TOKEN: the github access token for a user (preferably a functional ID) with push access to your project's git repository (used when pushing tags and commits). -
CP_USERNAME: theusernameportion of the Sonatype user token that you created earlier. -
CP_PASSWORD: thepasswordportion of the Sonatype user token that you created earlier. -
GPG_KEYNAME: this is the name/id of the signing key that will be used by the maven gpg plugin to sign your artifacts. The value used here should be the last 8 characters of the key name. For example, when I rungpg --list-keys, I see this output:
$ gpg --list-keys
/home/padams/.gnupg/pubring.kbx
-------------------------------
pub rsa2048 2020-11-22 [SC] [expires: 2022-11-22]
B265BB91D80124E463C63119EC4158B05D352E09
uid [ultimate] Phillip C. Adams <phil_adams@us.ibm.com>
sub rsa2048 2020-11-22 [E] [expires: 2022-11-22]
In this case, I would set the GPG_KEYNAME variable to 5D352E09.
GPG_PASSPHRASE: this is the passphrase associated with your signing key.
Note: when entering the values of environment variables, be sure to escape any special characters as instructed by the Travis build settings UI.
4.7: Commit your changes
After you have completed the above changes to your Java SDK project, you can commit the changes and push your feature branch, then open a pull request, etc. Feel free to tag Phil Adams as a reviewer on your pull request.
When committing your changes, be sure to use a commit message that will trigger a new
release when your pull request is merged and semantic-release processes your PR's commits
(e.g. git commit -m "feat(build): deploy artifacts to maven central" or something similar).
Do not merge your PR until the JIRA ticket you opened in step 2 is resolved (i.e. the Sonatype personnel have given your Sonatype account the necessary permission to publish artifacts).
5: Java SDK Build lifecycle overview
This section describes the various types of builds and build stages associated with the travis build configuration that you copied from the Java SDK Template repository.
Within the .travis.yml file, there are three main stages defined:
stages:
- name: Build-Test
- name: Semantic-Release
if: branch = master AND type = push AND fork = false
- name: Publish-Release
if: tag IS present
When you push a feature branch or open a pull request, the resulting travis build will run
only the Build-Test stage, which builds and unit tests the project.
When a pull request is merged into the master branch, the Build-Test stage is run,
and (assuming that was successful), the Semantic-Release stage is then run.
The Semantic-Release stage will run the semantic-release tool which will:
- Analyze the commit messages associated with the commits that were merged into the master branch since the most recent tagged-release of the project to determine if a new version (tagged-release) of the project is warranted.
- If a new version is needed, semantic-release will compile a changelog entry for the new version, perform some additional release management steps and will then push one or more commits back to the github repository along with a tag to represent the new version of the project.
The tag pushed by the semantic-release tool will trigger a "tagged-release"
Travis build. This build will run the Build-Test stage, then the Publish-Release stage.
The Publish-Release stage will then run two jobs in parallel:
- the
Publish-Javadocjob will produce javadocs from the project source, and then publish them on the git repository'sgh-pagesbranch. - the
Publish-To-Maven-Centraljob will publish the project's artifacts on Maven Central through the use of the nexus-staging-maven-plugin.
Appendix:
Using GitHub Actions instead of Travis-CI for your project's CI/CD
Due to occasional problems with the public Travis-CI service, some open-source IBM SDK projects have migrated from the public Travis-CI service to GitHub Actions for performing project builds. You can see an example of this in the IBM Cloud Platform Services Java SDK. If you choose to use GitHub Actions for your Java SDK project's CI/CD, this section will provide notes to help you adapt the instructions above which refer to Travis-CI.
- For an example workflow, see https://github.com/IBM/platform-services-java-sdk/tree/main/.github/workflows. There, you'll find:
- build.yaml - performs build and unit test
- publish.yaml - publishes new releases of the project
-
When using GH Actions, you won't need a
.travis.ymlfile, so that can be removed from your project. -
Instead of defining various secrets as environment variables in the Travis build settings, you will instead define these values as "Actions Secrets" (Settings->Secrets and variables->Actions within your git repo). Use the same names as those mentioned in the Travis instructions above:
GH_TOKEN,GPG_KEYNAME,GPG_PASSPHRASE,CP_USERNAME, andCP_PASSWORD. Note that the specific names mentioned here will work in conjunction with the examplepublish.yamlworkflow file mentioned above. If you choose to use different names for your secrets, just make sure that your workflow is adjusted accordingly. -
When using GH Actions, add your signing key to your git repository simply by adding the contents of the signing key file as a secret named
GPG_PRIVATE_KEY, rather than committing an encrypted version of the signing key file to your git repo as you would when using Travis-CI.
References:
- OSSRH Guide
- Deploying to OSSRH with Apache Maven
- Requirements (related to artifact publishing)
- Working with PGP Signatures
- Nexus Staging Maven Plugin for Deployment and Release
- Manual Staging Bundle Creation and Deployment
- General GitHub documentation
- Travis CI Documentation
- Travis CI Encrypting Files
- Travis CI Command Line Interface (CLI) Documentation
- Quickstart for GitHub Actions
- GitHub Actions documentation
- Using secrets in GitHub Actions