How to publish your Kotlin Multiplatform library on Maven Central

Vivien Mahé
6 min readFeb 23, 2024
JetBrains Kotlin Multiplatform + Sonatype Maven Central Repository + GitHub Actions

Whether you’re new to Kotlin Multiplatform development or you already have some experience with it, you might find yourself needing to create your own library for use in your projects or to make it publicly available.

If you come from the Java or Android world, you’re likely familiar with JitPack, a package repository for JVM and Android projects. JitPack automatically builds GitHub repositories and provides the artifacts through a regular Gradle dependency.

However, as of the date of this article, JitPack is not yet compatible with Kotlin Multiplatform. This is due to the fact that JitPack builds exclusively on Linux, not macOS, which is necessary for building native targets (e.g., iOS).

I do hope this limitation is addressed soon, as I appreciate JitPack for its simplicity and efficiency.

In the meantime, we must explore other options. One of the most popular alternatives is Maven Central, with Sonatype as the company behind it. Setting up your library for publication on Maven Central is unfortunately not as straightforward as with JitPack. However, through this article, I hope to demonstrate that the process is manageable after you’ve gone through it once.

Here’s a summary of the process explained in this article:

· Create your Sonatype account and register your namespace
· Configure GnuPG to sign your artifacts
· Configure Gradle for your library
· Publish your library to Maven Central via Github Actions
· Check your library on Maven Central

Create your Sonatype account and register your namespace

Since February 1st, 2024, Sonatype has changed the account creation process. It is no longer possible to create an account through https://issues.sonatype.org/, as this method is now considered legacy.

The first step is to create your Sonatype account, opting for the email/password option, as these credentials will be necessary later during the Gradle library configuration.

Next, you must select a namespace (also known as ‘groupId’). This namespace uniquely identifies your top-level project or organization among all other publishers on Maven Central.

For example, choosing the namespace io.github.mycompany means that all projects you publish on Maven Central will be part of this namespace. Thus, each project would be identified uniquely, for instance, as io.github.mycompany.myfirstproject, io.github.mycompany.mysecondproject, and so on.

➡️ To create your Sonatype account and get choose your namespace, follow the official instructions here: https://central.sonatype.org/register/central-portal/.

Click the Sign In button in the top right corner

Once you’re done with this process, you can retrieve your Staging Profile ID, which is required when Gradle will upload your artifacts to Maven Central.

➡️ Create and login to your Nexus account here: https://s01.oss.sonatype.org/ and get the Staging Profile ID from the URL.

Configure GnuPG to sign your artifacts

To publish an artifact on Maven Central, it must first be signed. This is accomplished using GnuPG (GPG), a free software that implements the OpenPGP standard.

You will need to generate a key pair with GPG to sign your artifacts and then distribute this key to a server, allowing users to verify its authenticity.

➡️ Follow the official instructions here: https://central.sonatype.org/publish/requirements/gpg/

After completing these steps, you will have:

  • A long-format keyId, which resembles something like this: CA925CD6C9E8D064FF05B4728190C4130ABA0F98 .
  • A passphrase which is the password you selected during the key pair creation process.
$ gpg --list-keys
/home/mylocaluser/.gnupg/pubring.kbx
---------------------------------
pub rsa3072 2021-06-23 [SC] [expires: 2023-06-23]
CA925CD6C9E8D064FF05B4728190C4130ABA0F98 # <-- The long-format keyId
uid [ultimate] Central Repo Test <central@example.com>
sub rsa3072 2021-06-23 [E] [expires: 2023-06-23]

Now that we have the long-format key ID and the passphrase, there’s one last requirement: the GPG secret key.

You can retrieve and export it to your clipboard with the following command:

# macOS
$ gpg --armor --export-secret-key central@example.com | pbcopy

# Ubuntu (assuming GNU base64)
$ gpg --armor --export-secret-key central@example.com | xclip

# Arch
$ gpg --armor --export-secret-key central@example.com | xclip -selection clipboard -i

# FreeBSD (assuming BSD base64)
$ gpg --armor --export-secret-key central@example.com | xclip

Configure Gradle for your library

Now that you’ve set up your Sonatype account and prepared GPG for artifact signing, the next step is to configure your library via Gradle. This enables Gradle to build the library, sign it with GPG, and publish it to Maven Central.

In a typical development workflow, it’s crucial to publish and test the library locally to ensure everything functions correctly before making a public release. Therefore, you need to set up Gradle to publish our library both to the local Maven repository (on your computer) and to Maven Central via your Sonatype account.

To begin with local publishing, open your local.properties file and add the following properties:

sonatype.username={INSERT HERE YOUR SONATYPE ACCOUNT USERNAME}
sonatype.password={INSERT HERE YOUR SONATYPE ACCOUNT PASSWORD}
sonatype.stagingProfileId={INSERT HERE YOUR SONATYPE STAGING PROFILE ID}
signing.key="{INSERT HERE YOUR GPG PRIVATE SIGNING KEY}"
signing.password="{INSERT HERE YOUR GPG SIGNING PASSPHRASE}"

Next, you must instruct Gradle on the destination for publishing the library on Maven Central. To do this, open your project’s root build.gradle.kts file and add the following lines:

import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties

plugins {
kotlin("multiplatform").version("1.9.21").apply(false)
id("com.android.library").version("8.1.4").apply(false)
id("org.jetbrains.dokka").version("1.9.10").apply(false)
id("io.github.gradle-nexus.publish-plugin").version("2.0.0-rc-1")
...
}

nexusPublishing {
repositories {
sonatype {
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
username.set(gradleLocalProperties(rootDir).getProperty("sonatype.username") ?: System.getenv("OSSRH_USERNAME"))
password.set(gradleLocalProperties(rootDir).getProperty("sonatype.password") ?: System.getenv("OSSRH_PASSWORD"))
stagingProfileId.set(gradleLocalProperties(rootDir).getProperty("sonatype.stagingProfileId") ?: System.getenv("OSSRH_STAGING_PROFILE_ID"))
}
}
}

Finally, you need to configure Gradle for the library’s publishing and GPG signing:

  • Dokka is used to automatically generate the library’s documentation, a requirement set by Sonatype for publishing.
  • Gradle is configured to generate the POM file, detailing the library’s name, description, license, developer information, etc.
  • The library is signed with GPG.

To implement these settings, open your library module’s build.gradle.kts file. Add the following lines, ensuring to modify the values as necessary:

To verify that this configuration is correctly set, you can deploy your library to your local Maven repository using the publishToMavenLocal Gradle task:

./gradlew publishToMavenLocal

Publish your library to Maven Central via GitHub Actions

This is the last step of this process. After testing your library and publishing it to your local Maven repository, you’re now ready to automate its publication to Maven Central using GitHub Actions.

First, configure the following GitHub Actions secrets within your repository:

  • OSSRH_GPG_SECRET_KEY: The generated secret key value.
  • OSSRH_GPG_SECRET_KEY_ID: The keyId of the generated secret key (only the last 16 characters).
  • OSSRH_GPG_SECRET_KEY_PASSWORD: The passphrase for your generated secret key.
  • OSSRH_PASSWORD: The password for your Sonatype account.
  • OSSRH_STAGING_PROFILE_ID: The staging profile ID assigned by Sonatype.
  • OSSRH_USERNAME: The username for your Sonatype account.

Next, proceed to create two GitHub Actions workflows:

  • buildRelease.yml: Build your KMP library. It will build the Android target on a Linux distribution and the iOS target on a MacOS.
  • publish.yml: Publish your KMP library on Maven Central. This workflow will be automatically executed when a new release version is created on your repository.

Check your library on Maven Central

With this, your library is now fully set up for automated publishing on Maven Central. After creating a release version of your library, it will be accessible via a URL provided by Sonatype. For example, in my case, the URL is:

https://repo1.maven.org/maven2/io/github/tweener/

You can include it in your projects as a dependency with the following line:

implementation("io.github.tweener:czan:2.1.0")

The source code is available on this GitHub repository. I encourage you to clone this template to create your own library!

For a practical example, check out C-ZAN, my open-source design system library for apps running on Compose Multiplatform:

I find the process of publishing to Maven Central somewhat challenging, but once you went through with it for your first library, it becomes much more straightforward for your next ones.

That’s all for this article! I hope you found it helpful, I would greatly appreciate your feedback! 🙏

Feel free to leave a comment below or reach out to me directly:

--

--

Vivien Mahé

Creating mobile apps while sharing my journey and learnings.