In this guide, we'll go through the entire process of making your Java, Kotlin, Android or any JVM-based library available to the wider developer community through the Maven Central repository. We'll cover everything from setting up your Sonatype account and getting familiar with the Central Portal to preparing your project and finally syncing it with Maven Central.
Maven Central is the go-to source for dependencies in the JVM ecosystem. By the end of the tutorial, you'll have the knowledge and tools to contribute to the repository and make your code accessible to millions of developers worldwide.
The guide focuses on projects using the Gradle build system, but most concepts are generic and will help even if you use a different system.
What is Sonatype?
Founded in 2008, Sonatype has established itself as a prominent player in the JVM software development landscape. While the company provides a suite of tools and services in many areas like supply chain management, quality and security, it is best known for its stewardship of the Maven Central repository.
The Maven Central repository is the primary artifact repository for Java and JVM-based projects. In this context, Sonatype acts as a gatekeeper, filtering, validating and approving new artifacts before they become available to the wider developer community. As such, it plays a fundamental role for the security and health of the whole ecosystem.
What is the Central Portal?
The process of publishing artifacts to Maven Central has historically been a pain point for many developers, especially because of lack of documentation. This lead to a steep learning curve for those attempting to release their projects to the repository.
The initial hurdles involve understanding Maven Central's complex requirements, registering projects to OSSRH (OSS Repository Hosting), setting up the appropriate credentials, signing artifacts with a PGP key and configuring build settings.
The Central Portal is Sonatype's new release process that marks a significant improvement. The revised procedure streamlines the entire publication workflow, making it more intuitive and modern. Notably, the new process is very well documented too.
For registrations newer than March 12th, 2024, publishing through the Central Portal is mandatory. Older projects can currently opt-in by emailing Sonatype's support.
How to publish to Maven Central
To publish to Maven Central you can follow the four steps below:
While some of these steps may not be trivial, they must only be performed once per publication namespace,
which typically spans many projects. For example, io.deepmedia:foo:1.0.0
and io.deepmedia:bar:1.0.0
are both
under the io.deepmedia
namespace.
For the last step, the presence of Gradle plugins like MavenDeployer makes configuration simpler and reusable across different projects.
Register a namespace
First of all, navigate to the Central Portal website and create a new account.
We recommend to use GitHub as a login provider, because in that case you should be automatically granted
a namespace that looks like io.github.<your username>
which may be useful.
Owning a namespace means that you (and importantly, no-one else) have the right to publish artifacts whose group
start with the namespace string. For example, owning the com.example
namespace would give you permission to
publish artifacts like com.example:project-name:1.0.0
or even com.example.project-name:project-name-api:1.0.0
.
To register a namespace:
-
In the namespaces section, you can add new namespaces in the reverse DNS form. If you own the
example.com
domain, usecom.example
. -
You'll see a verification code. Add it as a TXT record to your domain's DNS settings and let Sonatype verify it.
You now have publication rights for your domain!
Generate API tokens
The second step is to generate API tokens for API-based publication:
- Navigate to the account settings and click on Generate User Token.
- Save the generated username and password, as we'll use them later.
How to safely store these credentials? It depends:
- For CI access (e.g. GitHub actions), you may save them as secret environment variables through your CI provider web interface.
- Locally, you may put them in a
local.properties
file,.env
file or any other location that can be easily accessed from Gradle and isn't checked in your git repository.
Web UI based publications are also allowed, but using APIs through Gradle plugins will save you a lot of time and allow integration in your CI/CD pipeline.
Distribute PGP keys
In order to verify your publication artifacts, Maven Central requires that they are cryptographically signed with a public OpenPGP key. In simple terms, you are required to create a pair of keys:
- A secret key, to be used for artifact signing.
- A public key, to be distributed in online databases called keyservers.
The public key will be used by the Central Portal to verify that the published artifacts indeed came from you and haven't been tampered with. We recommend following the official guide for key-pair generation and public key distribution.
Then, you'll need to save your passphrase and your secret key in ASCII-armored format. To generate it, use the following command:
shellgpg --armor --export-secret-keys your-key-id
Both the passphrase and the armored key should be secretly stored, just like you have done with publication tokens.
For example, you can use environment variables in CI environments, and a local.properties
file for your developer machine.
Saving a multiline string in a properties file like
local.properties
requires replacing newlines with the\n
character.
Configure your Gradle build
At this point, you should have everything that you need to publish to Maven Central:
- An API token username, stored in an environment variable or Gradle property. For the purposes of this guide, let's say
the variable or property is named
UPLOAD_USERNAME
. - An API token password, in
UPLOAD_PASSWORD
. - A signing PGP passphrase, in
SIGNING_PASSPHRASE
. - A signing PGP armored private key, in
SIGNING_KEY
.
The only thing left is to put everything together in your Gradle-based project. For this task, we highly recommend using MavenDeployer or any other plugin that can configure your build to output and upload the right artifacts.
At this time, not many Gradle plugins support Central Portal uploads. Check the official list for more information.
First, apply the MavenDeployer plugin:
kotlin// settings.gradle.kts
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}
// build.gradle.kts of projects to be published
plugins {
id("io.deepmedia.tools.deployer") version "0.13.0"
}
Then configure projects that need to be published to Maven Central as follows:
kotlindeployer {
// 1. Artifact definition.
// https://opensource.deepmedia.io/deployer/artifacts
content { ... }
// 2. Project details.
// https://opensource.deepmedia.io/deployer/configuration
projectInfo {
description = "A sample project to showcase Maven Central publications."
url = "https://github.com/sample-company/SampleProject"
scm.fromGithub("sample-company", "SampleProject")
license(apache2)
developer("sampleUser", "sample@sample-company.com", "SampleCompany", "https://sample-company.com")
groupId = "com.sample-company"
}
// 3. Central Portal configuration.
// https://opensource.deepmedia.io/deployer/repos/central-portal
centralPortalSpec {
signing.key = secret("SIGNING_KEY")
signing.password = secret("SIGNING_PASSPHRASE")
auth.user = secret("UPLOAD_USERNAME")
auth.password = secret("UPLOAD_PASSWORD")
}
}
Let's talk about what's happening:
-
Artifact definition: this part is left as blank because it depends on your project (is it Java-based? Is it Kotlin-based? Do you use KMP?). You can learn more about it in the plugin's documentation. Keep in mind that Maven Central requires your main artifact to be accompanied by a Javadoc and a sources JAR. MavenDeployer can help you with these, too.
-
Project details: these details will be used to configure the publication POM file, which goes through strict validation when uploaded to the Central Portal. Most of them are mandatory. For example, a deployment without
developer
information will be rejected. Check the plugin documentation for more options. -
Portal coniguration: here we simply use the four variables that this guide helped you configure. Thanks to MavenDeployer's
secret
support, you can place them anywhere - in the system environment, in a Gradle property, even in alocal.properties
file - and the plugin will pick them up. Again, you can check the plugin documentation to learn more Central Portal options.
Once everything is properly configured, just run the deploy task:
shell./gradlew deployCentralPortal
The plugin takes care of collecting all artifacts - even across different subprojects! - prepare a single bundle and upload it to the Central Portal using the credentials that you have provided. It will also wait for Portal's validation and provide meaningful errors in case anything goes wrong.
Bonus: other repositories
It is worth noting that, with just a couple of extra lines, the plugin can help you publish your artifacts to other repositories:
- Sonatype Nexus repositories, which also include Maven Central sync, with
nexusSpec { ... }
- Sonatype Nexus snapshot repositories, with
nexusSpec { repositoryUrl = ossrhSnapshots1 }
- Github pcakages, with
githubSpec { ... }
- Local filesystem repositories, with
localSpec { ... }
We recommend you check the documentation to learn more.
Conclusions
Congratulations on reaching the end of this guide to publishing on Maven Central through the new Central Portal mechanism!
In this article, we have covered everything from PGP key generation and Maven Central's stringent requirements to Gradle build configuration. We described the whole publishing process, breaking it down into manageable steps that both novice and experienced developers can follow, so you can focus on what truly matters – creating outstanding libraries and contributing to the open-source ecosystem.
At DeepMedia, we believe in the power of open source to drive innovation within the developer community. By sharing this guide and our Gradle plugin, we hope to lower the barriers to entry for publishing on Maven Central, encouraging more developers to share their work.