LogoPortfolio
Home
Projects
Articles
Certificates
More
Contact
Back to Articles
AndroidMavenGradleAARpublish

Mastering Local Maven Publishing & Dependency Conflicts: A Kotlin Developer’s Guide

Published on June 7, 2025

Mastering Local Maven Publishing & Dependency Conflicts: A Kotlin Developer’s Guide

Managing dependencies is a critical part of software development, especially when working with modular projects. In this article, we’ll explore how to publish Kotlin libraries locally using Maven and Gradle, and tackle dependency version conflicts with practical examples. Let’s dive in!

Why Local Publishing Matters

Before deploying code to public repositories like Maven Central, developers often test their libraries locally. This allows for rapid iteration without cluttering remote repositories.

Another use case? Note that you can’t directly implement .aar file dependency in your project as your IDE will yell at you. So, the solution? Publish it locally and then implement it. Similarly, you may have your own use cases to do this.

Now, Let’s see how this works with a real-world scenario.

Step 1: Creating and Publishing a Library

Imagine you’re building three Kotlin modules:

  • Module A: Provides a utility function.

  • Module B: Depends on Module A.

  • Module C: Depends on Module B (and indirectly on A).

1. Module A (Version 1.0.0)

Here’s Abc.kt in Module A:

package com.example.test_maven_local.a

class Abc {
    fun first(): String {
        return "Hello from first"
    }
}

To publish it locally, configure build.gradle.kts:

// 1. Apply necessary plugins
plugins {
    id("maven-publish")       // Adds tasks to publish artifacts to Maven repositories
    `java-library`            // Provides Java compilation, testing, and packaging capabilities
    kotlin("jvm") version "1.9.0"  // Kotlin JVM support (ensure version matches your project's Kotlin)
}

// 2. Define Maven coordinates for your library
// - Group: Organizational identifier (e.g., your company domain reversed)
// - Version: Release version (follow Semantic Versioning: MAJOR.MINOR.PATCH)
group = "org.example.first"
version = "1.0.0"

// 3. Configure publishing settings
publishing {
    publications {
        // Create a Maven publication named "maven"
        create<MavenPublication>("maven") {
            // Package the JAR built from the Java/Kotlin source code
            from(components["java"])
            // Optional: Customize the artifact ID (defaults to project name)
            // artifactId = "my-library"
        }
    }

    repositories {
        // Define where to publish the artifact
        maven {
            // Publish to a local directory named "repo" in the project root
            // For team use, replace with a network path
            url = uri(File(projectDir, "repo"))
            // Optional: Add credentials for remote repositories
            // credentials {
            //     username = project.findProperty("repoUser") as String?
            //     password = project.findProperty("repoPassword") as String?
            // }
        }
    }
}

Now run ./gradlew publish. This generates a local Maven repository in the repo directory.

Step 2: Consuming the Published Library

After publishing Module A, you can reference it in Module B:

Module B’s Code

package com.example.test_maven_local.b

import com.example.test_maven_local.a.Abc // Import from the published JAR

class B {
    fun getValueFromA() = Abc().first()
}

In Module B’s build.gradle.kts, add and sync:

dependencies {
    implementation("org.example.first:app:1.0.0") // Published version
}

Key Insight: Even if you delete the source code of Abc.kt from Module A, Module B will still work because it now uses the compiled JAR from your local repository.

The Danger of Version Conflicts

What happens if you publish a new version of Module A (e.g., 1.0.1) with breaking changes?

Module A (Version 1.0.1)

class Abc {
    // The function `first()` is removed!
    fun newFunction(): String {
        return "New functionality"
    }
}

If Module B still depends on 1.0.0 but Module C wants 1.0.1, conflicts arise:

Module C’s Code

package com.example.test_maven_local.c

import com.example.test_maven_local.b.B

class C {
    fun test(): String {
        return B().getValueFromA() // B uses Abc 1.0.0, but C might want 1.0.1
    }
}

Resolving Conflicts: The Gradle Way

Gradle’s resolution strategy lets you enforce specific dependency versions. For example:

allprojects {
    configurations.configureEach {
        resolutionStrategy {
            force("org.example.first:app:1.0.0") // Force older version
        }
    }
}

But this isn’t foolproof! If Module C requires Abc 1.0.1 (which lacks first()), the app will crash at runtime.

Best Practices for Dependency Management

- Semantic Versioning: Increment versions correctly: MAJOR for breaking changes,MINOR for backward-compatible features,PATCH for bug fixes.

  • MINOR for backward-compatible features.

  • PATCH for bug fixes.

- Avoid Breaking Changes: If Module A must remove first(), create a new method instead of deleting the old one. - Use Dependency Alignment: Ensure all modules depend on the same library version. - Local Publishing Workflow: Test changes locally before pushing to remote repos. Use a structured directory (e.g., repo/) for local artifacts.

Publishing Android Libraries (.AAR)

The process is similar for Android! Replace java-library with com.android.library in Gradle and publish .aar files instead of .jar.

Conclusion

Local Maven publishing accelerates development but demands careful version management. By understanding resolution strategies and semantic versioning, you can avoid dependency hell.

Try it yourself:

  1. Publish two versions of a library, create scenarios and use resolutionStrategy to see how Gradle behaves.

Found this helpful? Consider following, clapping, and sharing your thoughts! Also, Don’t forget to like and comment your thoughts.

About

Professional portfolio showcasing my work, articles, and achievements.

Quick Links

  • Projects
  • Articles
  • Certificates
  • Contact

Connect

GitHubGitHubLinkedInMediumMedium

Subscribe

© 2026 Portfolio. All rights reserved.