I'm working on creating a library for a Kotlin Multiplatform project. Currently, the project is structured into four separate modules:
The goal is to build and distribute a library starting from the FeatureX module. I've tried two different approaches so far:
Publish all modules locally, then import only the FeatureX module in the consumer app.
Pros: It works as expected.
Cons: If the number of modules increases, I'll have to publish each one individually to Maven, which adds complexity and maintenance overhead.
Build a fat-AAR that includes everything FeatureX needs.
Pros: Only one module to publish.
Cons: Requires manually excluding unnecessary dependencies, packaging is more complex, and ultimately, this approach doesn't work reliably.
Do you have any suggestions on how to move forward? Would it be better to publish each module individually, even if only one is needed by the consumer? Or is there a cleaner way to package and publish the whole dependency tree more efficiently?
Thanks in advance!
EDIT: You can check out the official Android Fused Library Plugin to combine your modules into a single AAR. But I believe it's Android-only for now and still experimental.
I had this issue a few months back and I chose the "multiple modules" approach for our KMP library. Here’s why:
1. Simplicity. You've already mentioned it works for you and it's straightforward. Each module (core, network, featureX, etc.) becomes its own Maven artifact and Gradle’s transitive POM support means consumers only declare one dependency (e.g. featureX) and get everything it needs. No fat-AAR tricks means you avoid merging JARs or custom packaging hacks.
2. Second reason for me was better CI/CD reliability. Publishing 4+ small artifacts via maven-publish is trivial to script in your pipeline. If you use CI/CD, you pretty much don't have to worry about publishing individually since the script would just handle that. Also, since each module’s metadata (group, version, dependencies) lives with its code, you get fewer hidden gotchas than fat-AAR bundling.
3. It follows the ecosystem’s examples, I believe this was the deciding factor for me. So take a look at a popular library like Coil. Coil splits into coil-base, coil-gif, coil-svg, etc., and if you check the maven central repository, you get to see io.coil-kt:coil:2.7.0 has a published "core/base" module. Ktor, kotlinx.coroutines, Koin, and many others follow the same pattern, so of course, it's not unusual to follow suit.
Bonus: In my case, the requirement was to have the featureX modules be exposed to the consumers. Later on, an internal requirement came in which another team needed our network module code. This was easy to do since the network module was already it's own standalone artifact.
TL;DR
Pros: modular, easy versioning, Gradle just works fine with transitive APIs.
Cons: a bit more setup up front, but CI scripts handle it seamlessly.