# How Maven's Repository System Handles Artifact Resolution: A Deep Dive into the Source Code

> Understand how Maven's repository system resolves artifacts by exploring its seven-step pipeline, Eclipse Aether, and network operations. Learn the source code behind artifact resolution.

- Repository: [The Apache Software Foundation/maven](https://github.com/apache/maven)
- Tags: deep-dive
- Published: 2026-07-05

---

**Maven resolves artifacts through a seven-step pipeline that converts coordinates into downloaded files by orchestrating Eclipse Aether, version range resolution, and repository aggregation before delegating network operations to the underlying RepositorySystem.**

Maven's repository system serves as the backbone of Java dependency management, transforming declarative coordinates into concrete file artifacts. According to the Apache Maven source code, this resolution process is implemented primarily in `DefaultArtifactResolver` and related classes within the `org.apache.maven.api.services` package, leveraging the Eclipse Aether library (now Maven Resolver) for transport operations.

## The Seven-Step Resolution Pipeline

When a build requests an artifact—either directly via `ArtifactResolver` or indirectly during POM construction—Maven executes a well-defined sequence:

### 1. Coordinate Creation and Validation

The process begins with constructing `ArtifactCoordinates` from the requested **groupId**, **artifactId**, **version**, **classifier**, and **extension**. In [`DefaultArtifactResolver.java`](https://github.com/apache/maven/blob/main/DefaultArtifactResolver.java) at lines 99-102, the session converts these parameters into a structured coordinate object:

```java
ArtifactCoordinates coords = session.createArtifactCoordinates(
    "org.apache.commons", "commons-lang3", "3.12.0", null, "jar", null);

```

This coordinate object serves as the immutable identifier throughout the resolution lifecycle.

### 2. Repository Selection and Merging

Maven merges request-specific repositories with session defaults to determine the resolution scope. At lines 94-96 in [`DefaultArtifactResolver.java`](https://github.com/apache/maven/blob/main/DefaultArtifactResolver.java), the resolver aggregates configured remote repositories:

```java
List<RemoteRepository> repos = session.toResolvingRepositories(
    request.getRepositories() != null ? request.getRepositories()
                                      : session.getRemoteRepositories());

```

This step applies mirrors, proxies, and authentication settings configured in [`settings.xml`](https://github.com/apache/maven/blob/main/settings.xml).

### 3. Version Range Resolution

When the version specifies a range (e.g., `[1.0,)`), Maven delegates to the **VersionResolver** service. The `DefaultModelResolver` at lines 46-53 determines the highest reachable version before proceeding with artifact download:

```java
String newVersion = session.resolveHighestVersion(coords, repos)
                            .orElseThrow(...).toString();

```

This ensures deterministic resolution of dynamic dependencies.

### 4. Aether Request Construction

Maven populates an `ArtifactRequest` object with the resolved coordinates and repository list. Lines 99-102 in [`DefaultArtifactResolver.java`](https://github.com/apache/maven/blob/main/DefaultArtifactResolver.java) demonstrate this bridging between Maven's high-level API and Aether's transport layer:

```java
ArtifactRequest aReq = new ArtifactRequest();
aReq.setArtifact(session.toArtifact(coords));
aReq.setRepositories(repos);

```

### 5. Network Resolution and Download

The actual download occurs through `RepositorySystem.resolveArtifacts()` at lines 111-115 of [`DefaultArtifactResolver.java`](https://github.com/apache/maven/blob/main/DefaultArtifactResolver.java). This method contacts remote repositories sequentially, checking the local cache first, and returns an `ArtifactResult` containing the downloaded file:

```java
List<ArtifactResult> results = session.getRepositorySystem()
                                       .resolveArtifacts(session.getSession(),
                                                         resolverRequests);

```

### 6. Result Aggregation and Mapping

Maven wraps the Aether results into an `ArtifactResolverResult` mapping coordinates to `ResultItem` objects. Lines 52-55 in [`DefaultArtifactResolver.java`](https://github.com/apache/maven/blob/main/DefaultArtifactResolver.java) handle this transformation, capturing the downloaded artifact, source repository, and file path.

### 7. Error Handling and Diagnostics

If resolution fails, Maven aggregates exceptions into a `BatchRequestException` and throws an `ArtifactResolverException` with per-artifact diagnostics. Lines 122-130 in [`DefaultArtifactResolver.java`](https://github.com/apache/maven/blob/main/DefaultArtifactResolver.java) implement this error aggregation, providing detailed failure context for each repository attempted.

## Key Architectural Components

### DefaultArtifactResolver

The `DefaultArtifactResolver` class in [`impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java`](https://github.com/apache/maven/blob/main/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java) serves as the primary orchestration point. It handles request preparation, repository merging, Aether delegation, and result aggregation. Every resolution step is wrapped in `RequestTraceHelper` for debugging and logging.

### Version Resolution Services

The `DefaultVersionResolver` (lines 70-86) resolves version ranges by querying repository metadata. For parent POM resolution, `DefaultModelResolver` integrates this service to support semantic versioning constraints.

### Snapshot Handling

Before resolution, `RemoteSnapshotMetadataGenerator` computes timestamped snapshot versions. This class in [`impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/RemoteSnapshotMetadataGenerator.java`](https://github.com/apache/maven/blob/main/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/RemoteSnapshotMetadataGenerator.java) ensures that `-SNAPSHOT` dependencies resolve to the latest build timestamp available in remote repositories.

### InternalSession Bridge

[`InternalSession.java`](https://github.com/apache/maven/blob/main/InternalSession.java) bridges Maven's high-level `org.apache.maven.api` types with Aether's lower-level representations, converting coordinates, repositories, and artifacts between API boundaries.

## Practical Code Examples

### Resolving a Single Artifact

The following pattern resolves a specific artifact from default remote repositories:

```java
import org.apache.maven.api.ArtifactResolver;
import org.apache.maven.api.services.ArtifactResolverRequest;
import org.apache.maven.api.services.ArtifactResolverResult;
import org.apache.maven.api.Session;

// Assume `session` is injected by Maven’s DI container.
ArtifactResolver resolver = session.lookup(ArtifactResolver.class);

ArtifactResolverRequest request = ArtifactResolverRequest.builder(session)
        .addCoordinates(
            session.createArtifactCoordinates("org.apache.commons", "commons-lang3",
                                             "3.12.0", null, "jar", null))
        .build();

ArtifactResolverResult result = resolver.resolve(request);
result.getArtifacts().forEach(a -> System.out.println("Downloaded: " + a.getPath()));

```

This corresponds to the implementation at `DefaultArtifactResolver.resolve` (lines 60-66).

### Resolving Parent POM Models

When building a POM hierarchy, Maven uses `ModelResolver` to fetch parent descriptors:

```java
import org.apache.maven.api.services.ModelResolver;
import org.apache.maven.api.services.ModelResolverRequest;
import org.apache.maven.api.services.ModelResolverResult;
import org.apache.maven.api.model.Parent;

ModelResolver modelResolver = session.lookup(ModelResolver.class);

Parent parent = new Parent()
        .setGroupId("org.apache.maven")
        .setArtifactId("maven-model")
        .setVersion("[1.0,)");
ModelResolverRequest mr = new ModelResolverRequest(session, null, null,
        parent.getGroupId(), parent.getArtifactId(),
        parent.getVersion(), null, "pom");

ModelResolverResult mrResult = modelResolver.resolveModel(mr);
System.out.println("Parent POM path: " + mrResult.source().getPath());

```

This triggers version-range resolution at `DefaultModelResolver.doResolveModel` (lines 46-53).

### Programmatic SNAPSHOT Resolution

To resolve the latest version of a SNAPSHOT artifact:

```java
import org.apache.maven.api.services.VersionResolver;
import org.apache.maven.api.services.VersionResolverRequest;
import org.apache.maven.api.services.VersionResolverResult;

VersionResolver versionResolver = session.lookup(VersionResolver.class);

VersionResolverRequest vr = VersionResolverRequest.builder(session)
        .setArtifactCoordinates(session.createArtifactCoordinates(
                "org.apache.maven", "maven-core", "[3.6-SNAPSHOT,)", null, "jar", null))
        .build();

VersionResolverResult vrResult = versionResolver.resolve(vr);
System.out.println("Resolved version: " + vrResult.getVersion());

```

This utilizes `DefaultVersionResolver` (lines 70-86) for timestamped snapshot selection.

## Summary

- **Maven delegates transport operations** to Eclipse Aether (Maven Resolver) through the `RepositorySystem` interface, while maintaining high-level APIs in `org.apache.maven.api.services`.
- **Version ranges resolve** to concrete versions before artifact download via `DefaultVersionResolver`, ensuring reproducible builds.
- **Repository aggregation** merges request-specific, profile-specific, and global repositories with mirror/proxy configuration at resolution time.
- **Snapshot artifacts** trigger special metadata generation to determine the latest timestamped build before download.
- **Comprehensive error handling** aggregates per-repository failures into `ArtifactResolverException` with detailed diagnostics for debugging resolution failures.

## Frequently Asked Questions

### How does Maven prioritize which remote repository to use for artifact resolution?

Maven uses the aggregated list of repositories from the project POM, parent POMs, and settings.xml, applying mirrors and proxies configured in [`settings.xml`](https://github.com/apache/maven/blob/main/settings.xml). The `DefaultArtifactResolver` at lines 94-96 merges these sources into a single `List<RemoteRepository>` that Aether queries sequentially until the artifact is found.

### What happens when Maven encounters a version range like `[1.0,)` in a dependency?

Maven invokes `DefaultVersionResolver` to query repository metadata and determine the highest matching version available. As shown in `DefaultModelResolver` (lines 46-53), the resolver calls `session.resolveHighestVersion()` to select the concrete version before constructing the download request.

### Where does Maven store artifacts after downloading them from remote repositories?

Downloaded artifacts are stored in the local repository (typically `~/.m2/repository`) after successful resolution. The `ArtifactResult` returned by `RepositorySystem.resolveArtifacts()` contains the `DownloadedArtifact` with the local file path, which `DefaultArtifactResolver` maps into the final `ArtifactResolverResult` at lines 52-55.

### How does Maven handle SNAPSHOT dependencies differently from release artifacts?

SNAPSHOT versions trigger special metadata resolution via `RemoteSnapshotMetadataGenerator` before the actual artifact download. This class computes the timestamped version (e.g., `1.0-SNAPSHOT` becomes `1.0-20230115.123456-1`) by querying repository metadata, ensuring the latest build is retrieved while maintaining cache coherence.