# Maven Repositories

> Use a CloudRepo Maven repository from Maven: settings.xml, pom.xml, publishing, overwrite protection, the 409 Conflict, snapshot cleanup and proxies.

Publish your Maven builds to CloudRepo and resolve your dependencies from it. Maven needs three things: the credential in `settings.xml`, the repository URL in `pom.xml`, and one command.

## Before you start

- A Maven repository. If you have none, see [Creating a Repository](/docs/manage/repositories.html#creating-a-repository).
- A repository token that reaches it, with **Read + write** if you will publish. See [Repository Tokens: Create One and Authenticate](/docs/authenticate/repository-tokens.html). The username is the email address of the account that created the token, and the password is the token.
- Your repository URL, `https://your-org.mycloudrepo.io/repositories/your-repo`. The [Connection Settings](/docs/manage/repositories.html#view-connection-settings) of the repository show it with your names filled in.

> **Note:** Use a repository token, not a password. An organization owner’s portal password is not accepted at a package door. A token the owner creates works like anyone else’s.

## Connect Maven

**Maven**

**1. Put the credential in `~/.m2/settings.xml`.** The `<id>` is a name you choose, and it must match the `<id>` of the repository in your `pom.xml`. `${env.CLOUDREPO_TOKEN}` reads the token from an environment variable, so the token is not in the file; you can paste the token there instead.

`~/.m2/settings.xml`

```xml
<settings>
  <servers>
    <server>
      <id>cloudrepo</id>
      <username>you@example.com</username>
      <password>${env.CLOUDREPO_TOKEN}</password>
    </server>
  </servers>
</settings>
```

Maven reads `~/.m2` by default. If you moved the local repository, put the file where your Maven looks for it. To keep a pasted token out of plain text, encrypt it by following Maven’s [password encryption guide](https://maven.apache.org/guides/mini/guide-encryption.html).

**2. Name the repository in `pom.xml`.** Repositories in `<repositories>` are where Maven retrieves artifacts from:

`pom.xml`

```xml
<repositories>
  <repository>
    <id>cloudrepo</id>
    <url>https://your-org.mycloudrepo.io/repositories/your-repo</url>
  </repository>
</repositories>
```

The repository in `<distributionManagement>` is where `mvn deploy` publishes:

`pom.xml`

```xml
<distributionManagement>
  <repository>
    <id>cloudrepo</id>
    <url>https://your-org.mycloudrepo.io/repositories/your-repo</url>
  </repository>
</distributionManagement>
```

If you have a parent POM, put both blocks there so you write them once.

**3. Publish.** Run this in the directory of your `pom.xml`:

**Terminal**

```bash
mvn --batch-mode deploy
```

Expected: `BUILD SUCCESS`, and the artifact is listed in the repository in the [admin portal](https://admin.cloudrepo.io). Maven retrieves from the `<repositories>` entry during any build that needs a dependency from this repository, so there is nothing more to run for that.

**Optional: fetch a file with curl.** To fetch a file directly rather than through Maven, send the same credential. Put it in `~/.netrc` and ask curl to read it:

`~/.netrc`

```ini
machine your-org.mycloudrepo.io
login you@example.com
password YOUR_REPOSITORY_TOKEN
```

Then fetch the file. Replace the path after `/repositories/your-repo/` with your artifact’s group, name and version, and keep `~/.netrc` readable by you alone (`chmod 600 ~/.netrc`):

**Terminal**

```bash
curl --netrc --fail --output docs-maven-1.0.0.jar \
  https://your-org.mycloudrepo.io/repositories/your-repo/com/example/docs/docs-maven/1.0.0/docs-maven-1.0.0.jar
```

> **Note:** Each file you publish to a Maven repository can be up to 50 GB (50,000,000,000 bytes). A larger file is refused with `413`.

## Use Gradle

Gradle reads a CloudRepo Maven repository with the same URL and a repository token. The [Gradle tab of Repository Tokens](/docs/authenticate/repository-tokens.html) has a ready-to-paste `build.gradle.kts` and `build.gradle`, and [Gradle Repositories](/docs/repository-types/jvm/gradle-repositories.html) covers publishing.

## Maven Repository Settings

In addition to the [Standard Settings](/docs/manage/repositories.html#repository-settings) of every repository, a Maven repository has Snapshot Cleanup and Overwrite Protection.

### Maven Snapshot Cleanup

A snapshot is a version that ends in `-SNAPSHOT`. Each deploy of a snapshot version writes a new build, so a repository that is built often collects many builds of the same snapshot. A release version has one build.

In the repository’s settings, turn on **Snapshot Cleanup** and set **Snapshots to keep per GAV**, from 1 to 10: the number of builds to keep for each snapshot version of an artifact.

### Maven Overwrite Protection

[Overwrite Protection](/docs/manage/repositories.html#overwrite-protection) is on by default for a Maven repository: a repository that has not turned it off is protected, whenever it was created. With it on, publishing a release artifact to a coordinate that already holds one is refused with `409 Conflict`, and the artifact already in the repository is left as it is.

#### Publish refused: status code 409, reason phrase Conflict

If a `mvn deploy` has just failed and the only explanation in the output is this:

```text
status code: 409, reason phrase: Conflict
```

you have republished a release version into a repository with Overwrite Protection on, which is the default. CloudRepo sends an explanation in the response body (`Version already exists. Overwrites are disabled for this repository.`), but Maven prints only the status code and the reason phrase and discards the rest.

Nothing is broken. Your credentials and the repository are fine: the server refused to replace a release artifact that already exists, and the artifact already in the repository is left as it is. It is a policy refusal, not a fault.

Three ways forward, in the order that is usually right:

1. **Publish a new version.** Almost always the right answer. A release that someone else’s build has already used should not change under them.
2. **Use a `-SNAPSHOT` version while you iterate.** Snapshot versions are exempt and may be republished as often as you build.
3. **Turn Overwrite Protection off for that repository,** from the **Overwrite Protection** card in its settings, if it is meant to accept republished releases. The cost: a publish then replaces an existing release without a refusal, so a build that resolved that coordinate yesterday can get different bytes today.

Two things are exempt, because Maven rewrites both on every publish:

- **Snapshot versions.** A version ending in `-SNAPSHOT` may always be overwritten, which is what gives Snapshot Cleanup several builds to count.
- **`maven-metadata.xml`,** with its `.md5`, `.sha1`, `.sha256`, `.sha512` and `.asc` sidecars. These index files are rewritten each time you publish a new version.

A checksum or signature that belongs to an artifact, such as `my-app-1.0.0.jar.sha1`, is not exempt. It is written once with its release and protected along with it.

## Maven Proxy Repositories

A proxy repository passes requests through CloudRepo to a public Maven repository you choose from a curated list: Maven Central, Google Maven, Gradle Plugins, Clojars, Confluent, Atlassian, Spring and others. See [Proxy Repositories](/docs/consume/proxy-repositories.html).

---

The page: https://www.cloudrepo.io/docs/formats/maven.html
