Maven

What is a Maven Repository? The Complete Guide for 2026

A Maven repository is a directory that stores build artifacts. Learn how Maven repositories work, the difference between local and remote repositories, and how to set up your own private Maven repository.

CloudRepo Team
18 min read
Last updated: April 11, 2026

A Maven repository is a directory that stores Java build artifacts (JARs, WARs, POMs) organized by group ID, artifact ID, and version, so Maven can resolve and download dependencies automatically. The three types are local (on your machine at ~/.m2/repository), remote (over HTTP/HTTPS), and Maven Central (the default public source).

If you work with Java, Kotlin, Scala, or any JVM project, you have already used Maven repositories. Every mvn compile checks one. This guide explains how Maven repositories work, what each type is for, how dependency resolution actually happens, and when a team needs a private repository of its own.

What are Maven artifacts?

An artifact is any file produced by a build process that another project might need. In the Maven world, the word covers more than just JARs:

  • JAR files: Java Archive files containing compiled classes and resources
  • WAR files: Web Application Archives for servlet containers like Tomcat or Jetty
  • EAR files: Enterprise Archive files for Java EE application servers
  • POM files: Project Object Model descriptors that record metadata, dependencies, and build configuration
  • Source archives: *-sources.jar bundles that IDEs use for “Jump to Source”
  • Documentation: *-javadoc.jar bundles that publish API reference docs
  • Test artifacts: *-tests.jar bundles so downstream projects can reuse test fixtures
  • Native binaries: .so, .dll, or .dylib files bundled for JNI dependencies

Every artifact is uniquely identified by three coordinates, the Maven GAV (GroupId, ArtifactId, Version):

  • groupId: The organization or project namespace, usually a reverse-DNS string (e.g., org.springframework, com.google.guava)
  • artifactId: The specific module name within that group (e.g., spring-core, guava)
  • version: The release number, optionally with a -SNAPSHOT suffix for in-development builds (e.g., 6.2.1, 1.0.0-SNAPSHOT)

Together, these three values form a coordinate like org.springframework:spring-core:6.2.1. That coordinate is what you paste into a pom.xml dependency block, and it is exactly how the artifact is stored on disk: Maven replaces dots with slashes, appends the artifactId and version, and lands at a path like /org/springframework/spring-core/6.2.1/spring-core-6.2.1.jar. Every Maven-compatible tool (Gradle, sbt, Leiningen, Ivy) uses the same layout.

Some artifacts also carry a classifier, a suffix that distinguishes flavors of the same GAV, for example linux-x86_64 vs windows-x86_64. Classifiers show up on native libraries and multi-platform packages.

What is Maven?

Apache Maven is more than a build tool. It is a project management framework that standardizes how Java projects are described, built, tested, and published. Three of its responsibilities touch repositories directly.

1. Automates dependency management

Instead of manually downloading JAR files and dropping them into a lib/ folder, Maven fetches the exact versions your project needs from repositories you configure. Add a dependency block, run any build goal, and Maven handles the rest.

pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.2.1</version>
</dependency>
</dependencies>

Transitive dependencies are resolved automatically: if spring-core depends on spring-jcl, Maven downloads both without you ever writing down the second coordinate.

2. Provides a standard project structure

Maven enforces a conventional directory layout so every Maven project looks the same to every Java developer:

my-project/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ └── resources/
│ └── test/
│ ├── java/
│ └── resources/
└── target/

This convention over configuration is why a senior engineer can open any Maven project and immediately know where the source code, tests, and compiled output live.

3. Manages the build lifecycle

Maven defines a standard lifecycle with ordered phases:

  • validate: Check that the project is correct and all necessary information is available
  • compile: Compile source code into target/classes/
  • test: Run unit tests with the test framework (usually JUnit)
  • package: Bundle the compiled code into a JAR or WAR
  • verify: Run integration tests and quality checks
  • install: Install the artifact into the local repository so other projects on your machine can use it
  • deploy: Upload the artifact to a remote repository so your team can use it

The last two phases, install and deploy, are where repositories enter the picture. Without a repository to install into, Maven cannot let one module on your machine depend on another. Without a repository to deploy to, your team cannot share internal libraries.

What is a Maven repository, exactly?

A Maven repository is a structured storage location that holds Maven artifacts according to their coordinates. Think of it as a library where books (artifacts) are organized by publisher (groupId), title (artifactId), and edition (version). Maven tools read from and write to repositories the same way. Whether the repository is a folder on your laptop or a cloud service halfway across the world, the layout and protocol are identical.

Tip

Maven repositories use a specific directory structure: /groupId/artifactId/version/artifactId-version.jar. For example: /org/springframework/spring-core/6.2.1/spring-core-6.2.1.jar. Gradle, sbt, and most other JVM build tools follow the same layout, so a Maven repository is really a JVM ecosystem repository.

What are the types of Maven repositories?

Most teams encounter three layers (local, central, and remote), but in practice the landscape is richer. Below is a side-by-side comparison of the repository types you will run into, followed by a closer look at each.

Types of Maven repositories

Type Location / access One-sentence definition
Local repository ~/.m2/repository on your machine A per-developer cache of every artifact Maven has downloaded or installed, checked first on every build.
Maven Central repository https://repo.maven.apache.org/maven2/ The default public source for open-source JVM libraries, hosting 10 million+ artifacts and requiring no configuration.
Remote repository Any HTTP/HTTPS URL you add to pom.xml or settings.xml A generic category for any repository served over the network, whether public, private, corporate, or third-party.
Private repository A URL hosted by your team, e.g. https://repo.acme.com A network repository that requires authentication and stores proprietary code your organization does not want exposed publicly.
Nexus-hosted repository Nexus OSS or Nexus Pro server, on-prem or self-hosted A repository managed by Sonatype Nexus, typically deployed in a datacenter or VPC under your team’s operational control.
Google Maven repository https://maven.google.com/ Google’s public repository for Android libraries (AndroidX, Jetpack, Firebase), required for Android Gradle builds.
Private-hosted repository A fully managed cloud service such as CloudRepo A private repository run as SaaS, so you pay for storage and access control without owning any infrastructure or patching any servers yourself.
Mirror repository Any repository declared as <mirrorOf>*</mirrorOf> A caching proxy sitting in front of one or more upstream repositories, used to speed up builds and reduce egress from external sources.
Snapshot repository Usually a subtree of a private repository A repository that accepts -SNAPSHOT versions and overwrites prior builds, used for in-development artifacts that change frequently.

Each of these types plays a different role in a team’s workflow. The three classical types (local, central, remote) are the ones most articles cover, but understanding the rest clarifies why real-world setups get complex.

1. Local repository

The local repository lives on your development machine, typically at ~/.m2/repository. It is the first place Maven checks on every build, and it does three jobs:

  • Caches downloaded artifacts so the next build does not re-download the internet
  • Stores locally-installed builds created by mvn install, so sibling projects can depend on them without a remote repository in the loop
  • Acts as the first-level cache in the resolution order, where a hit means zero network traffic

Because the local repository is per-developer, two engineers on the same team can have slightly different artifacts in their ~/.m2/ directories. That is usually fine, but when “works on my machine” becomes a debate, comparing local repository contents is a great place to start investigating.

2. Maven Central repository

Maven Central, at https://repo.maven.apache.org/maven2/, is the default public repository for the JVM ecosystem. When you add a dependency without declaring any other source, Maven goes to Central.

  • Contains 10 million+ open-source artifacts across 500,000+ packages
  • Maintained by Sonatype on behalf of the Maven community
  • No configuration required, Maven uses it by default
  • Searchable at search.maven.org
  • Free to download from and free to publish to (with strict validation rules)

3. Remote repositories

“Remote” is the umbrella term for any repository accessed over a network. Maven treats them all the same way; the difference is who runs them and who can read from them.

  • Corporate repositories: Internal company artifacts shared across teams
  • Third-party repositories: Vendor-specific artifacts (Oracle, Atlassian, JBoss)
  • Mirror repositories: Geographic or cached mirrors of Central
  • Private repositories: Commercial services like CloudRepo or self-hosted Nexus
  • Google Maven: The Android ecosystem’s public repository at maven.google.com

Info

Android builds using Gradle automatically add the Google Maven repository on top of Maven Central. If you are a backend Java developer wondering why your Android-building colleagues have maven.google.com in their config, this is why.

How do you configure Maven repositories?

There are two places to declare repositories: inside a project’s pom.xml (project-scoped) and inside ~/.m2/settings.xml (user-scoped). The choice matters: project repositories travel with the project in version control, while settings repositories apply only to your machine.

In your POM

Adding a repository directly to pom.xml is the most explicit option and makes the project self-contained:

pom.xml
<repositories>
<repository>
<id>my-company-repo</id>
<url>https://mycompany.mycloudrepo.io/repositories/maven-releases</url>
</repository>
</repositories>

This approach works well when the repository is public or when credentials are managed elsewhere (e.g., injected by CI). It does not support credentials directly; authentication always lives in settings.xml.

In settings.xml

For credentials, user-level profiles, or repositories you want active across all projects, use ~/.m2/settings.xml:

~/.m2/settings.xml
<settings>
<servers>
<server>
<id>my-company-repo</id>
<username>user</username>
<password>pass</password>
</server>
</servers>
<profiles>
<profile>
<id>company</id>
<repositories>
<repository>
<id>my-company-repo</id>
<url>https://mycompany.mycloudrepo.io/repositories/maven-releases</url>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>company</activeProfile>
</activeProfiles>
</settings>

The id in <server> must match the id in <repository>. That is how Maven knows which credentials to send to which URL. A common source of authentication bugs is an id mismatch between the two, usually a typo or a copy-paste leftover from a different project.

How does Maven resolve dependencies?

When Maven encounters a dependency declaration, it runs an ordered resolution process to decide where to fetch the artifact from. Understanding this order is the difference between quickly debugging a missing artifact and staring at error messages for an hour.

The resolution order

For any given dependency, Maven walks through these locations in sequence and stops at the first hit:

  1. Local repository first. Maven checks ~/.m2/repository for the exact GAV coordinate. If the artifact and its POM are present and the checksums validate, resolution ends here, with no network traffic at all. This is why your second build is always faster than your first.
  2. Configured repositories in declaration order. If the local cache misses, Maven walks through the repositories declared in your pom.xml and active profiles in the order they appear. Declaration order matters: the first repository that returns a 200 OK wins, so fast or authoritative sources should be listed first.
  3. Maven Central as the fallback. Unless you have explicitly disabled it, Central is always in the resolution chain. Maven falls back to Central for any artifact not found in local or configured repositories.
  4. Mirrors intercept the whole chain. If you have configured a mirror with <mirrorOf>*</mirrorOf>, the mirror replaces whatever repository Maven would have otherwise contacted. A mirror is not an additional source; it is a substitution.

What happens on a cache miss

When the local cache misses and Maven contacts a remote repository, it downloads two things: the POM and the primary artifact. The POM is critical because it lists the dependency’s own dependencies, which Maven then resolves recursively. A single mvn install on a fresh project can trigger hundreds of POM downloads as Maven walks the transitive dependency graph. This is the cold-start cost you pay on a freshly cloned project.

Downloaded artifacts are stored in the local repository immediately and validated with the checksum files (.sha1, .md5) that accompany them. A checksum mismatch is a hard error by default in strict mode; more on that in the security section below.

Releases vs snapshots

The rules change for snapshot versions. A release version (e.g., 1.0.0) is immutable: once published, the artifact at that coordinate must never change. Maven treats releases as permanent cache entries and never re-checks the remote.

A snapshot version (e.g., 1.0.0-SNAPSHOT) is mutable: it represents the latest build of an in-development branch. Maven checks snapshot repositories on a configurable interval (daily by default, via the updatePolicy setting) and pulls fresh copies when available. The behavior lets developers share the latest build with teammates without cutting a release every time, but it also means snapshot builds are not reproducible in the way releases are. If you need a byte-for-byte reproducible build, pin everything to release versions.

You can force a refresh with mvn -U clean install, which tells Maven to re-check all snapshot repositories regardless of the update policy.

Public vs private Maven repositories

Public repositories

Public repositories serve open-source artifacts to anyone on the internet, no authentication required:

  • Maven Central: The primary public repository for the JVM ecosystem
  • JCenter: Popular alternative during 2010–2021, now sunset
  • Spring Repositories: Official source for Spring Framework and Spring Boot artifacts
  • Google’s Maven repository: AndroidX, Jetpack, and Firebase libraries for Android builds

Private repositories

Private repositories are essential as soon as your team writes code you do not want the whole world to see:

  • Security: Keep source code and compiled artifacts confidential
  • Access control: Manage who inside the company can read and publish
  • Compliance: Meet regulatory requirements around software supply chain and IP handling
  • Performance: Download from a repository closer to your build infrastructure
  • Stability: Cache third-party artifacts so upstream outages do not break your builds

Important

Never publish proprietary code to public repositories. Once an artifact lands in a public index, it is effectively public forever, and even removing it from the repository does not undo external caches.

How do repository managers compare?

Most teams eventually pick a repository manager to run their private Maven repositories. The options split across deployment model, feature set, and pricing philosophy. Rather than anchoring on dollar figures (which change constantly and depend on usage patterns), the comparison below focuses on how each option actually helps a team.

Repository manager capability comparison

Manager Caching / proxy Access control SSO Egress model
CloudRepo Proxy and caching of Central and other upstreams Per-repository roles, user and team based On our roadmap (all plans) Flat-rate with soft limits (no egress fees)
Nexus OSS Local caching, manual proxy configuration Role-based, limited user groups Not included Self-hosted, you pay for bandwidth
Nexus Pro Advanced staging, smart proxy, cleanup policies Fine-grained roles, LDAP, custom Included in Pro tier Self-hosted, you pay for bandwidth
JFrog Artifactory Enterprise-grade remote and virtual repositories Fine-grained, project and permission based Included on Pro tier and above Consumption-based, egress metered separately
GitHub Packages Proxy limited to GitHub Container Registry Tied to GitHub org roles Available via GitHub Enterprise Included in GitHub plans, with metered tiers

A few notes to put the table in context:

  • Caching and proxy is the feature that makes a repository manager worth deploying at all. Without it, every developer and CI job re-downloads the same JAR from Central. Every manager above offers some form of caching; the differences are how much control you get over cache rules and third-party proxying.
  • Access control matters as teams grow past a handful of engineers. You will eventually need repositories only certain projects can publish to, or read-only credentials for CI. Nexus OSS covers the basics; Nexus Pro, Artifactory, and CloudRepo all provide finer-grained control.
  • SSO is table-stakes for enterprise buyers but usually a paid upgrade. If your security team requires SAML or OIDC, budget for a commercial tier.
  • Egress model is where costs compound unexpectedly. Consumption-based pricing turns a busy CI pipeline into a surprising line item. Flat-rate trades a higher base price for predictability. Self-hosted tools shift egress onto your cloud bill; the cost does not disappear, it just moves.

For how pricing actually plays out over a year, see our JFrog Artifactory pricing guide and Sonatype Nexus pricing guide.

Best practices for Maven repositories

1. Use a repository manager

Even small teams benefit from running (or subscribing to) a repository manager in front of Central: it caches artifacts to speed up builds, reduces load on upstream repositories, provides a single point of configuration, and adds security scanning and access control without modifying every project.

2. Separate snapshots and releases

Keep release versions and snapshot versions in different repositories so you can apply different retention policies and different read/write rules:

<distributionManagement>
<repository>
<id>releases</id>
<url>https://mycompany.mycloudrepo.io/repositories/maven-releases</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<url>https://mycompany.mycloudrepo.io/repositories/maven-snapshots</url>
</snapshotRepository>
</distributionManagement>

Release repositories should be immutable and retained forever. Snapshot repositories can aggressively prune older builds; typically, only the most recent handful of snapshots per module need to stay available.

3. Use dependency management

Centralize version numbers in a parent POM so every module inherits a consistent version matrix. Teams that skip this step end up with three versions of guava in a single build:

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.2.1</version>
</dependency>
</dependencies>
</dependencyManagement>

4. Enable strict checksum policies

Ensure artifact integrity by requiring checksum validation on every download:

<checksumPolicy>fail</checksumPolicy>

With fail, Maven aborts the build on any checksum mismatch. With warn (the default on some setups), Maven logs a warning and continues, which is acceptable for experimentation but dangerous for production.

5. Use remote caching for CI/CD

Repository managers double as remote caches for your build infrastructure, which is where they really earn their keep:

~/.m2/settings.xml
<!-- Configure a mirror to cache all external requests -->
<mirrors>
<mirror>
<id>cloudrepo-cache</id>
<mirrorOf>*</mirrorOf>
<url>https://mycompany.mycloudrepo.io/repositories/maven-cache</url>
</mirror>
</mirrors>

Benefits of remote caching:

  • Faster builds: Artifacts sit closer to your build infrastructure
  • Reliability: Builds no longer depend on external repository availability
  • Security: Scan artifacts once at the cache layer instead of on every download
  • Cost control: Reduce egress traffic to external repositories

6. Use a Bill of Materials (BOM) for version management

For complex projects with many related dependencies, import a BOM to manage compatible versions across the whole family:

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.4.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

A BOM is a POM with <packaging>pom</packaging> that declares a consistent set of dependency versions. Spring Boot, Jakarta EE, and the AWS SDK for Java all publish BOMs so downstream consumers can pin one version and get a known-good matrix.

Common use cases for Maven repositories

1. Corporate library sharing

Share common libraries across teams: utility code, company frameworks built on Spring or Jakarta EE, shared data models, and internal API clients generated from OpenAPI or gRPC specs.

2. Third-party and commercial dependencies

Manage licensed commercial libraries that cannot be published to Maven Central: Oracle JDBC drivers, commercial UI libraries, licensed analytics components, and vendor SDKs distributed as JAR files.

3. Build promotion across environments

Promote artifacts through environments by copying them between repositories: dev snapshots, staging release candidates, production releases. Build promotion is cleaner than rebuilding from source at every environment: the same byte-for-byte artifact moves from dev through staging to prod, eliminating “it built differently this time” as a failure mode.

CI/CD integration with Maven repositories

Modern CI/CD pipelines depend on fast, reliable access to Maven repositories. Every build downloads dependencies, and slow or unreliable repositories can bottleneck your entire development process.

Why repository performance matters for CI/CD

Consider a typical pipeline:

  • 10 builds per hour across your team
  • 200 MB of dependencies downloaded per build
  • 60 GB of transfer per month just for dependencies

With consumption-based pricing (like JFrog Artifactory), this transfer alone can cost hundreds of dollars monthly. With flat-rate pricing (like CloudRepo), you pay the same regardless of download volume, and CI pipelines tend to generate far more download traffic than any single developer’s machine does.

GitHub Actions with Maven

Here is a complete GitHub Actions workflow that builds, tests, and deploys to a private Maven repository:

name: Maven Build and Deploy
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Configure Maven Settings
run: |
mkdir -p ~/.m2
cat > ~/.m2/settings.xml << EOF
<settings>
<servers>
<server>
<id>cloudrepo-releases</id>
<username>\${{ secrets.MAVEN_USERNAME }}</username>
<password>\${{ secrets.MAVEN_PASSWORD }}</password>
</server>
<server>
<id>cloudrepo-snapshots</id>
<username>\${{ secrets.MAVEN_USERNAME }}</username>
<password>\${{ secrets.MAVEN_PASSWORD }}</password>
</server>
</servers>
</settings>
EOF
- name: Build and Test
run: mvn -B verify
- name: Deploy to Repository
if: github.ref == 'refs/heads/main'
run: mvn -B deploy

Tip

The cache: maven option in setup-java caches your ~/.m2/repository directory between builds, significantly speeding up subsequent runs. The cache key is hashed from your pom.xml files, so it invalidates automatically when dependencies change.

GitLab CI with Maven

GitLab CI configuration for Maven projects with private repository deployment:

image: maven:3.9-eclipse-temurin-21
variables:
MAVEN_CLI_OPTS: '-s .m2/settings.xml --batch-mode'
MAVEN_OPTS: '-Dmaven.repo.local=.m2/repository'
cache:
paths:
- .m2/repository/
stages:
- build
- test
- deploy
build:
stage: build
script:
- mvn $MAVEN_CLI_OPTS compile
test:
stage: test
script:
- mvn $MAVEN_CLI_OPTS verify
deploy:
stage: deploy
script:
- mvn $MAVEN_CLI_OPTS deploy
only:
- main
- tags

Create .m2/settings.xml in your repository:

<settings>
<servers>
<server>
<id>cloudrepo-releases</id>
<username>${env.MAVEN_USERNAME}</username>
<password>${env.MAVEN_PASSWORD}</password>
</server>
<server>
<id>cloudrepo-snapshots</id>
<username>${env.MAVEN_USERNAME}</username>
<password>${env.MAVEN_PASSWORD}</password>
</server>
</servers>
</settings>

CI/CD best practices for Maven repositories

  1. Use dependency caching: Both GitHub Actions and GitLab CI support caching the local repository
  2. Never hardcode credentials: Use secrets or environment variables for authentication
  3. Choose repositories without egress fees: CI/CD generates massive download volume
  4. Mirror external repositories: Reduce external calls and improve reliability
  5. Use parallel builds wisely: Configure mvn -T 4 for multi-threaded builds on multi-core runners

How do you troubleshoot Maven repository issues?

Artifact not found

When Maven reports that an artifact is missing, the usual fix is forcing a refresh of the local cache:

Terminal window
# Force update of snapshots
mvn clean install -U
# Skip the local cache entirely
mvn clean install -Dmaven.repo.local=/tmp/m2

The -U flag tells Maven to re-check all remote repositories even if they were recently checked. This is useful when a snapshot has been redeployed or when the update policy would otherwise skip a check.

Authentication problems

Most authentication bugs come from an id mismatch between <server> and <repository>:

<server>
<id>repository-id-must-match</id>
<username>correct-username</username>
<password>correct-password</password>
</server>

The id in <server> must match the id in <repository> or <mirror> exactly. Maven matches them by string, not by URL. If you see 401 errors but the credentials are correct, the id is the first place to look. The second place is whether the credentials are URL-encoded correctly if the password contains special characters.

Slow downloads

  • Use a repository manager as a proxy so downloads happen once per artifact, not once per developer
  • Configure mirrors that live geographically close to your build infrastructure
  • Increase Maven’s thread count: mvn -T 4 clean install parallelizes module builds
  • Check network latency between your CI runners and your repository, since a cross-region hop can add hundreds of milliseconds per request

Corrupt artifacts

If a downloaded artifact is corrupt (a truncated JAR, a wrong checksum), delete its directory from the local repository and let Maven re-download:

Terminal window
rm -rf ~/.m2/repository/org/springframework/spring-core/6.2.1
mvn clean install

If the same artifact keeps corrupting, the problem is upstream: check whether a proxy or mirror is rewriting content.

Security considerations for Maven repositories

Maven repositories are part of your software supply chain, which means their security directly affects your production systems. A compromised repository can inject malicious code into every build that depends on it.

Use HTTPS for every remote repository

Every remote repository URL must be https://, never http://. Since Maven 3.8.1, plain HTTP repositories are blocked by default; Maven refuses to download from them and fails the build. Teams that suppress this to “get unblocked” are inviting man-in-the-middle attacks. If you inherit a legacy project that references an HTTP-only repository, find the HTTPS equivalent or mirror the artifacts internally and serve them over HTTPS from your own repository manager. Do not override the HTTP block globally.

Enforce checksum policies

Maven downloads .sha1 or .md5 checksums alongside every artifact and validates them after the download completes. The <checksumPolicy> setting controls what happens on a mismatch:

  • fail: Reject the artifact and fail the build. The correct choice for production CI and any repository serving releases.
  • warn: Log a warning and keep going. Acceptable for experimentation, dangerous for production because it normalizes checksum errors that might indicate tampering.
  • ignore: Skip checksum validation entirely. Never use this.

Where available, configure tooling to use the stronger SHA-256 and SHA-512 checksums some managers publish alongside SHA-1.

Defend against dependency confusion attacks

Dependency confusion is a supply-chain attack named by security researcher Alex Birsan in 2021. An attacker identifies the name of a private internal package, publishes a malicious package with the same name but a higher version to a public repository, and waits for a build configured to check both sources to pull the attacker’s copy. Birsan demonstrated the attack against 35+ major companies including Apple, Microsoft, and PayPal.

Defenses for Maven builds:

  • Use a dedicated groupId prefix for internal artifacts (e.g., com.acme.internal.*) and configure your repository manager to refuse to proxy artifacts matching that prefix from any external source
  • Lock down resolution order so internal repositories are checked first and Central is never consulted for internal groupIds
  • Run a caching proxy in front of Central so the groupId block is enforced consistently across all builds
  • Validate published artifacts by cross-checking signatures against the internal publication record before releasing

Dependency confusion is not a Maven-specific problem; it has been demonstrated against npm, PyPI, RubyGems, and NuGet. Maven teams are especially vulnerable when they treat pom.xml as the only source of truth and do not audit the repository configuration their builds actually use.

Rotate credentials and use scoped tokens

Repository passwords in settings.xml are a classic source of leaks: they show up in CI logs, in copied-and-pasted snippets, and in screen shares. Modern repository managers including CloudRepo support API tokens that are scoped to a single repository and can be rotated without changing the underlying user password. Use them.

When you need a private Maven repository

If you have read this far, you already understand what a Maven repository is and how Maven finds artifacts in one. The next question, the one that makes this decision real, is whether your team needs a private Maven repository of its own.

The answer is yes as soon as any of the following is true:

  • You publish Java libraries that cannot live on Maven Central. Central is for open-source artifacts with OSS licenses. Proprietary code, licensed SDKs, and unreleased internal modules do not belong there. If you have a jar your customers should not download, you need somewhere else to put it.
  • You share libraries across teams or services. The moment two Maven projects at your company need to depend on a third, you need a place to publish the third. Checking compiled JARs into Git works for one project but collapses under multi-repo coordination.
  • Your CI pipeline burns time and money hitting Maven Central directly. Every build that goes to the public internet pays a latency and reliability tax. A private Maven repository with caching turns that into a one-time download per artifact: your builds get faster, your bill shrinks, and an upstream outage stops being a 2am page.
  • Your security or compliance team requires an inventory of every dependency you ship. Private repository managers track exactly which artifacts exist, who can publish them, and who has downloaded them, the raw material of a credible SBOM process.
  • You have an SLA your upstream cannot meet. Maven Central is free and mostly reliable, but “mostly” is not a service level. If your business depends on builds succeeding at 3am, you need a repository you control or a vendor that owns the uptime.

The cheapest way to start is CloudRepo’s cloud-hosted Maven repository service, which gives you a private, authenticated Maven repository in minutes, with flat-rate pricing, no egress metering, and caching for Central built in. Self-hosting Nexus or Artifactory is also an option, but remember to budget for the people and infrastructure that will keep the server patched, backed up, and available.

The critical thing is not which vendor you pick. It is recognizing that once your team crosses any of the thresholds above, the cost of not having a private repository starts compounding. Ad-hoc solutions (shared folders, copied JARs, “just build it locally”) work until they do not, and the day they stop working is usually the day of a production deploy.

Getting started with CloudRepo

Ready to set up your own private Maven repository? CloudRepo makes it simple:

  1. Create a repository

    • Sign up for CloudRepo
    • Create a new Maven repository
    • Get your repository URL
  2. Configure Maven Add to your pom.xml:

    <distributionManagement>
    <repository>
    <id>cloudrepo</id>
    <url>https://[your-org].mycloudrepo.io/repositories/maven-releases</url>
    </repository>
    </distributionManagement>
  3. Deploy artifacts

    Terminal window
    mvn clean deploy

Frequently Asked Questions

What is the difference between a local and remote Maven repository?

A local Maven repository is a directory on your development machine (default location: ~/.m2/repository) that caches downloaded artifacts and stores locally-installed builds. Maven checks the local repository first before making network requests.

A remote Maven repository is accessed over HTTP/HTTPS and can be either public (like Maven Central) or private (like CloudRepo). Remote repositories are the source of truth for shared artifacts that teams need to access.

Key differences:

Aspect Local Repository Remote Repository
Location Your machine (~/.m2/repository) Network server
Purpose Cache and local builds Shared artifact storage
Access Immediate, no network Requires network
Shared Single developer Entire team/organization

How do I set up a private Maven repository?

To set up a private Maven repository:

  1. Choose a repository manager: Options include CloudRepo (cloud-hosted), Nexus, or Artifactory
  2. Create your repository: Configure a releases and snapshots repository
  3. Add credentials to settings.xml:
<servers>
<server>
<id>my-private-repo</id>
<username>your-username</username>
<password>$YOUR_API_TOKEN</password>
</server>
</servers>
  1. Configure distributionManagement in pom.xml:
<distributionManagement>
<repository>
<id>my-private-repo</id>
<url>https://your-repo-url/releases</url>
</repository>
</distributionManagement>
  1. Deploy with: mvn deploy

CloudRepo offers a 14-day free trial to get started with private Maven repositories in minutes.

What is the default Maven repository location?

The default local repository location is ~/.m2/repository on Unix/Mac systems and C:\Users\{username}\.m2\repository on Windows.

You can change this location in your ~/.m2/settings.xml:

<settings>
<localRepository>/custom/path/to/repository</localRepository>
</settings>

Or override it per-build with: mvn install -Dmaven.repo.local=/tmp/m2

The default remote repository is Maven Central at https://repo.maven.apache.org/maven2/.

How do I add a custom repository to Maven?

You can add custom repositories in two places:

Project-level (pom.xml) - affects only this project:

<repositories>
<repository>
<id>custom-repo</id>
<url>https://mycompany.mycloudrepo.io/repositories/maven-releases</url>
</repository>
</repositories>

User-level (settings.xml) - affects all your projects:

<profiles>
<profile>
<id>custom-repos</id>
<repositories>
<repository>
<id>custom-repo</id>
<url>https://mycompany.mycloudrepo.io/repositories/maven-releases</url>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>custom-repos</activeProfile>
</activeProfiles>

For private repositories, also add authentication in the <servers> section.

What is Maven Central and why is it important?

Maven Central (also called “Central Repository”) is the default public repository for Maven, located at https://repo.maven.apache.org/maven2/. It’s important because:

  • Default source: Maven downloads from Central automatically without configuration
  • Massive scale: Hosts over 10 million artifacts from 500,000+ packages
  • Trusted: Strict publishing requirements ensure artifact integrity
  • Free: No cost to download or publish open-source libraries
  • Searchable: Browse at search.maven.org

When you add a dependency like Spring Framework to your pom.xml, Maven retrieves it from Central unless you’ve configured an alternative repository.

Info

While Maven Central is essential for open-source dependencies, organizations typically need a private repository (like CloudRepo) for proprietary code that shouldn’t be publicly accessible.

Conclusion

Maven repositories are the backbone of dependency management in Java projects. They provide a standardized way to store, share, and retrieve artifacts, making it easier to:

  • Manage dependencies efficiently
  • Share code between projects and teams
  • Maintain version control
  • Ensure build reproducibility

Whether you are using public repositories for open-source dependencies or private repositories for proprietary code, understanding Maven repositories is essential for effective Java development.

Want the bigger picture? See our comprehensive Artifact Management Guide to understand how Maven repositories fit into a complete artifact management strategy, including Docker, npm, PyPI, and more.

Starting a new project? Check out our guide to the Best Private Maven Repository for Small Teams for a comparison of your options.


Ready to host your own private Maven repositories? Try CloudRepo free and see how easy repository management can be. With flat, all-inclusive pricing, no egress fees, and included support, CloudRepo gives teams predictable costs compared to consumption-based alternatives like JFrog Artifactory.

Ready for flat, predictable repository hosting?

Join the teams who've switched to CloudRepo for better pricing and features.

Related Articles

Maven

Maven vs Gradle Repository: Key Differences

Learn the differences between Maven and Gradle repositories, how each build tool handles dependency management, and which approach works best for your Java projects.

6 min read Read more →