---
url: /en/artifact/maven.md
description: >-
  Guide for configuring credentials and using the CNB Maven artifact registry to
  push and pull Java/JVM packages with Maven or Gradle, covering local
  development and CI pipeline workflows.
---
## Prerequisites

1. [Create Artifact Registry](./intro.md#creating-an-artifact-registry)
2. [Obtain Artifact Registry Address](./intro.md#obtaining-the-artifact-registry-address)
3. [Create Access Token](./intro.md#creating-an-access-token)

## Local Development

### Configure Credentials

::: tabs
@tab Maven

Copy the following content to the settings.xml file, replace `<YOUR_TOKEN>` with your token, and `<REPO_URL>` with the Artifact Registry address.

```xml
<settings>
  <servers>
    <server>
      <id>cnb-maven-repo</id>
      <username>cnb</username>
      <!-- Replace with your access token -->
      <password><YOUR_TOKEN></password>
    </server>
  </servers>
  <profiles>
    <profile>
      <id>cnb-maven-repo-profile</id>
      <repositories>
        <repository>
          <!-- Must match the server's id -->
          <id>cnb-maven-repo</id>
          <!-- Replace with the Artifact Registry address -->
          <!-- Example 
          <url>https://maven.cnb.cool/cnb/maven-repo/-/packages/</url>
          -->
          <url><REPO_URL></url>
        </repository>
      </repositories>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
    </profile>
  </profiles>
</settings>
```

@tab Gradle kotlin

1. Configure the token in gradle.properties in the project root directory, replace `<YOUR_TOKEN>` with your token.

```properties
cnbArtifactsGradlePassword=<YOUR_TOKEN>
```

2. Paste the following content into build.gradle.kts, replace `<REPO_URL>` with the Artifact Registry address.

```kotlin
publishing {
    repositories {
        maven {
            val cnbArtifactsGradlePassword = project.findProperty("cnbArtifactsGradlePassword")
            
            // Example
            // url = uri("https://maven.cnb.cool/cnb/maven-repo/-/packages/")
            url = uri("<REPO_URL>")
            credentials {
                username = "cnb"
                password = cnbArtifactsGradlePassword.toString()
            }
        }
    }
}
```

@tab Gradle groovy

1. Configure the token in gradle.properties in the project root directory, replace `<YOUR_TOKEN>` with your token.

```properties
cnbArtifactsGradlePassword=<YOUR_TOKEN>
```

2. Paste the following content into build.gradle, replace `<REPO_URL>` with the Artifact Registry address.

```groovy
publishing {
      repositories {
        maven {
            def cnbArtifactsGradlePassword = project.findProperty('cnbArtifactsGradlePassword')

            // Example 
            // url = uri("https://maven.cnb.cool/cnb/maven-repo/-/packages/")
            url = uri('<REPO_URL>')
            credentials {
                username = 'cnb'
                password = cnbArtifactsGradlePassword.toString()
            }
        }
    }
}
```

:::

### Pull Artifacts

::: tabs
@tab Maven

1. Configure the package you need to pull in pom.xml.

```xml
<dependencies>
    <dependency>
        <groupId>[GROUP_ID]</groupId>
        <artifactId>[ARTIFACT_ID]</artifactId>
        <version>[VERSION]</version>
    </dependency>
</dependencies>

<!-- Example
<dependencies>
    <dependency>
        <groupId>org.cnb</groupId>
        <artifactId>maven_demo</artifactId>
        <version>9.0.0</version>
    </dependency>
</dependencies> -->
```

2. Pull artifacts.

```shell
mvn clean install
# If using a specific settings.xml, execute:
mvn clean install -s ./settings.xml
```

@tab Gradle kotlin

1. Configure the dependencies you need in build.gradle.kts.

```kotlin
dependencies {
  implementation("[GROUP_ID]:[ARTIFACT_ID]:[VERSION]")
}

// Example
// dependencies {
//  implementation("com.google.guava:guava:32.1.3-jre")
// }
```

2. Pull artifacts.

```bash
./gradlew build --refresh-dependencies
```

@tab Gradle groovy

1. Configure the dependencies you need in build.gradle.

```groovy
dependencies {
    implementation '[GROUP_ID]:[ARTIFACT_ID]:[VERSION]'
}

// Example
// dependencies {
//   implementation 'com.google.guava:guava:32.1.3-jre'
// }
```

2. Pull artifacts.

```bash
./gradlew build --refresh-dependencies
```

:::

### Push Artifacts

::: tabs
@tab Maven

1. Configure the publishing repository and artifact properties in pom.xml, replace `<REPO_URL>` with the Artifact Registry address.

```xml
<project>
  <modelVersion>4.0.0</modelVersion>
  <!-- Artifact properties -->
  <groupId>[GROUP_ID]</groupId>
  <artifactId>[ARTIFACT_ID]</artifactId>
  <version>[VERSION]</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <!-- Publishing repository -->
  <distributionManagement>
    <repository>
      <!-- Must match the server's id in settings.xml -->
      <id>cnb-maven-repo</id>
      <name>cnb-maven-repo</name>
      <!-- Example 
      <url>https://maven.cnb.cool/cnb/maven-repo/-/packages/</url>
      -->
      <url><REPO_URL></url>
    </repository>
  </distributionManagement>
</project>
```

2. Push artifacts.

```shell
mvn deploy
# If using a specific settings.xml, execute:
mvn deploy -s ./settings.xml
```

@tab Gradle kotlin

1. Paste the following content into build.gradle.kts.

```kotlin
plugins {
    `java-library`
    `maven-publish`
}

group = "[GROUP_ID]"
version = "[VERSION]"
val artifactName = "[ARTIFACT_ID]"

publishing {
    publications {
        create<MavenPublication>("myLibrary") {
            groupId = group.toString()
            version = version.toString()
            artifactId = artifactName
            from(components["java"])
        }
    }
}
```

2. Execute the upload command.

```shell
./gradlew publish
```

@tab Gradle groovy

1. Paste the following content into build.gradle.

```groovy
plugins {
    id 'java-library'
    id 'maven-publish'
}

group = '[GROUP_ID]'
version = '[VERSION]'
def artifactName = '[ARTIFACT_ID]'

publishing {
    publications {
        myLibrary(MavenPublication) {
            groupId = group
            version = version
            artifactId = artifactName
            from components.java
        }
    }
}
```

2. Execute the upload command.

```shell
./gradlew publish
```

:::

## Cloud Native Build

### Configure Credentials

Cloud Native Build supports three ways to use tokens. Refer to [Using Tokens in Cloud Native Build and Development](./intro.md#using-tokens-in-workspaces-and-cloud-native-build). Below are the specific client usage methods:

::: tabs
@tab Maven

Replace `<REPO_URL>` with the Artifact Registry address.

```xml
<settings>
  <servers>
    <server>
      <id>cnb-maven-repo</id>
      <username>cnb</username>
      <!-- Method 1: Use built-in environment variable CNB_TOKEN -->
      <password>${env.CNB_TOKEN}</password>
      <!-- Method 2: Directly use, replace <YOUR_TOKEN> with your token -->
      <!--<password><YOUR_TOKEN></password>-->
      <!-- Method 3: Secret store, replace <ENV_NAME> with your secret store variable -->
      <!--<password>${env.<ENV_NAME>}</password>-->
    </server>
  </servers>
  <profiles>
    <profile>
      <id>cnb-maven-repo-profile</id>
      <repositories>
        <repository>
          <!-- Must match the server's id -->
          <id>cnb-maven-repo</id>
          <!-- Example
          <url>https://maven.cnb.cool/cnb/maven-repo/-/packages/</url>
          -->
          <url><REPO_URL></url>
        </repository>
      </repositories>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
    </profile>
  </profiles>
</settings>
```

@tab Gradle kotlin

Replace `<REPO_URL>` with the Artifact Registry address.

```kotlin
publishing {
    repositories {
        maven {
            // Method 1: Use built-in environment variable CNB_TOKEN
            val cnbArtifactsGradlePassword = System.getenv("CNB_TOKEN")
            // Method 2: Directly use, replace <YOUR_TOKEN> with your token
            // val cnbArtifactsGradlePassword = "<YOUR_TOKEN>"
            // Method 3: Secret store, replace <ENV_NAME> with your secret store variable
            // val cnbArtifactsGradlePassword = System.getenv("ENV_NAME")

            // Example 
            // url = uri("https://maven.cnb.cool/cnb/maven-repo/-/packages/")
            url = uri("<REPO_URL>")
            credentials {
                username = "cnb"
                password = cnbArtifactsGradlePassword.toString()
            }
        }
    }
}
```

@tab Gradle groovy

Replace `<REPO_URL>` with the Artifact Registry address.

```groovy
publishing {
      repositories {
        maven {
            // Method 1: Use built-in environment variable CNB_TOKEN
            def cnbArtifactsGradlePassword = System.getenv("CNB_TOKEN")
            // Method 2: Directly use, replace <YOUR_TOKEN> with your token
            // def cnbArtifactsGradlePassword = '<YOUR_TOKEN>'
            // Method 3: Secret store, replace <ENV_NAME> with your secret store variable
            // def cnbArtifactsGradlePassword = System.getenv("ENV_NAME")

            // Example 
            // url = uri("https://maven.cnb.cool/cnb/maven-repo/-/packages/")
            url = uri('<REPO_URL>')
            credentials {
                username = 'cnb'
                password = cnbArtifactsGradlePassword.toString()
            }
        }
    }
}
```

:::

### Pull Artifacts

Paste the following content into .cnb.yml:
::: tabs

@tab Maven

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: maven:3.8.5-openjdk-17
      stages:
        - name: mvn package
          script:
            mvn clean install -s ./settings.xml
```

@tab Gradle

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: gradle:7.6.6-jdk17
      stages:
        - name: gradle build and run
          script:
            - ./gradlew build --refresh-dependencies
```

:::

### Push Artifacts

Paste the following content into .cnb.yml:

::: tabs
@tab Maven

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: maven:3.8.5-openjdk-17
      stages:
        - name: mvn package
          script:
            mvn clean deploy -s ./settings.xml
```

@tab Gradle

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: gradle:7.6.6-jdk17
      stages:
        - name: gradle publish
          script:
            - ./gradlew publish
```

:::

## Workspaces

### Configure Credentials

Same as [Cloud Native Build Configure Credentials](./maven.md#configure-credentials-1)

### Configure Development Image

```yaml title=".cnb.yml"
$:
  vscode:
    - docker:
        image: maven:3.8.5-openjdk-17
```

### Pull Artifacts

Same as [Local Development Pull Artifacts](./maven.md#pull-artifacts)

### Push Artifacts

Same as [Local Development Push Artifacts](./maven.md#push-artifacts)

## Examples

### Gradle Local Push APK Package

1. Configure the android-application plugin in gradle/libs.versions.toml.

```toml
[versions]
agp = "8.11.1"
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
```

2. Configure the maven-publish plugin and apk packaging plugin in build.gradle or build.gradle.kts.
   ::: tabs
   @tab Gradle kotlin

```kotlin
// build.gradle.kts
plugins {
    id("com.android.application") // APK packaging plugin
    id("maven-publish") 
}
```

@tab Gradle groovy

```groovy
// build.gradle
plugins {
    id 'com.android.application'  // APK packaging plugin
    id 'maven-publish'
}
```

:::
3\. Configure the build task and push address in build.gradle or build.gradle.kts.
::: tabs
@tab Gradle kotlin

```kotlin
// build.gradle.kts
afterEvaluate {
    publishing {
        publications {
            create<MavenPublication>("releaseApk") {
                groupId = "cnb"
                artifactId = "artifact"
                version = "1.0.0"

                // For signed apps, use outputs/apk/release/${project.name}-release.apk
                val apkFile = layout.buildDirectory.file(
                    "outputs/apk/release/${project.name}-release-unsigned.apk"
                ).get().asFile

                artifact(apkFile) {
                    builtBy(tasks.named("assembleRelease"))
                    classifier = "release"
                    extension = "apk"
                }
            }
        }
        repositories {
            maven {
                // Declare cnbArtifactsGradlePassword in gradle.properties or export CNB_TOKEN=${YOUR_TOKEN}
                val cnbArtifactsGradlePassword = System.getenv("CNB_TOKEN") ?: project.findProperty("cnbArtifactsGradlePassword")

                // Example 
                // url = uri("https://maven.cnb.cool/cnb/maven-repo/-/packages/")
                url = uri("<REPO_URL>")
                credentials {
                    username = "cnb"
                    password = cnbArtifactsGradlePassword.toString()
                }
            }
        }
    }
}
```

@tab Gradle groovy

```groovy
// build.gradle
afterEvaluate {
    publishing {
        publications {
            releaseApk(MavenPublication) {
                groupId = 'cnb'
                artifactId = "artifact"
                version = '1.0.0'

                // For signed apps, use outputs/apk/release/${project.name}-release.apk
                def apkFile = layout.buildDirectory.file(
                    'outputs/apk/release/${project.name}-release-unsigned.apk'
                ).get().asFile

                artifact(apkFile) {
                    builtBy tasks.assembleRelease
                    classifier = 'release'
                    extension = 'apk'
                }
            }
        }
        repositories {
            maven {
                // Declare cnbArtifactsGradlePassword in gradle.properties or export CNB_TOKEN=${YOUR_TOKEN}
                def cnbArtifactsGradlePassword = System.getenv('CNB_TOKEN') ?: project.findProperty('cnbArtifactsGradlePassword')

                // Example 
                // url = uri("https://maven.cnb.cool/cnb/maven-repo/-/packages/")
                url = '<REPO_URL>'
                credentials {
                    username = 'cnb'
                    password = cnbArtifactsGradlePassword.toString()
                }
            }
        }
    }
}
```

:::
4\. Execute the following command.

```bash
./gradlew publish
```

### Gradle Local Push AAR Package

1. Configure the android-library plugin in gradle/libs.versions.toml.

```toml
[versions]
agp = "8.11.1"
[plugins]
android-library = { id = "com.android.library", version.ref = "agp" }
```

2. Configure the aar packaging plugin and maven-publish plugin in build.gradle or build.gradle.kts.
   ::: tabs
   @tab Gradle kotlin

```kotlin
// build.gradle.kts
plugins {
    id("com.android.library") // AAR packaging plugin
    id("maven-publish") 
}
```

@tab Gradle groovy

```groovy
// build.gradle
plugins {
    id 'com.android.library'  // AAR packaging plugin
    id 'maven-publish'
}
```

:::

3. Configure the build task and push address in build.gradle or build.gradle.kts.
   ::: tabs
   @tab Gradle kotlin

```kotlin
// build.gradle.kts
afterEvaluate {
    publishing {
        publications {
            create<MavenPublication>("releaseAar") {
                groupId = "cnb"
                artifactId = "artifact"
                version = "1.0.0"

                from(components["release"])
            }
        }
        repositories {
            maven {
                // Declare cnbArtifactsGradlePassword in gradle.properties or export CNB_TOKEN=${YOUR_TOKEN}
                val cnbArtifactsGradlePassword = System.getenv("CNB_TOKEN") ?: project.findProperty("cnbArtifactsGradlePassword")

                // Example 
                // url = uri("https://maven.cnb.cool/cnb/maven-repo/-/packages/")
                url = uri("<REPO_URL>")
                credentials {
                    username = "cnb"
                    password = cnbArtifactsGradlePassword.toString()
                }
            }
        }
    }
}
```

@tab Gradle groovy

```groovy
// build.gradle
afterEvaluate {
    publishing {
        publications {
            releaseAar(MavenPublication) {
                groupId = 'cnb'
                artifactId = "artifact"
                version = '1.0.0'

                from components.release
            }
        }
        repositories {
            maven {
                // Declare cnbArtifactsGradlePassword in gradle.properties or export CNB_TOKEN=${YOUR_TOKEN}
                def cnbArtifactsGradlePassword = System.getenv('CNB_TOKEN') ?: project.findProperty('cnbArtifactsGradlePassword')

                // Example 
                // url = uri("https://maven.cnb.cool/cnb/maven-repo/-/packages/")
                url = uri("<REPO_URL>")
                credentials {
                    username = 'cnb'
                    password = cnbArtifactsGradlePassword.toString()
                }
            }
        }
    }
}
```

:::

4. Execute the following command.

```bash
./gradlew publish
```

## FAQ

### After overwriting an existing version, the dependency build still uses the pre-overwritten version?

This is a Maven mechanism. If the local cache exists, it won't pull from the remote repository. There are three solutions:

1. Use the `--update-snapshots` command to force Maven to check for updates of snapshot dependencies in the remote repository. This strategy only works for SNAPSHOT versions.

```bash
mvn clean package -U
```

2. Remove the cached package by deleting the local Maven cache.

```bash
# macOS and Linux default location: ~/.m2
# Windows default location: C:\Users\{username}\.m2\repository
# Or query with the following command:
mvn help:evaluate -Dexpression=settings.localRepository
```

3. Set the `updatePolicy` to `always` in settings.xml for the dependency repository. This strategy only works for SNAPSHOT versions.

```xml
<settings>
  <profiles>
    <profile>
      <id>cnb-maven-repo-profile</id>
      <repositories>
        <repository>
          <id>cnb-maven-repo</id>
          <url><REPO_URL></url>
          <!-- Configure snapshot pull policy -->
          <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
          </snapshots>
        </repository>
      </repositories>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
    </profile>
  </profiles>
</settings>
```

### Encountered 409 Forbidden?

You have already uploaded this package, and overwriting is prohibited. To overwrite the package, go to the corresponding Artifact Registry -> Registry Settings -> Strategy:

* To overwrite only SNAPSHOT versions, select `Maven Snapshot Strategy`.
* To overwrite both SNAPSHOT and RELEASE versions, select `Allow overwriting of all existing versions`.

## More Usage

For more Maven usage, refer to the official Maven documentation.
