# How Maven Configures and Uses Wagon for Repository Transport

> Learn how Maven configures Wagon for repository transport by parsing settings.xml and using Aether. Understand Wagon's role in Maven's build process.

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

---

**Maven configures Wagon transport by parsing `<server>` configurations from *settings.xml* into `PlexusConfiguration` objects, passing them to Aether's `WagonTransporterFactory` via properties prefixed with `aether.transport.wagon.config.<serverId>`, and delegating protocol-specific operations to `Wagon` implementations looked up through the `WagonManager` interface.**

Apache Maven uses the Eclipse Aether (now Maven Resolver) engine to resolve dependencies and deploy artifacts. While modern Maven versions default to the Apache HttpClient transporter, the **Wagon** framework remains fully supported as an alternative transport layer for repository operations over HTTP, SSH, SCP, and file protocols.

## Enabling Wagon Transport Mode

Maven selects its transport implementation based on the `maven.resolver.transport` system property. To force the use of Wagon instead of the default Java HTTP client, set the property at launch:

```bash
mvn clean deploy -Dmaven.resolver.transport=wagon

```

According to the source code in [`DefaultRepositorySystemSessionFactory.java`](https://github.com/apache/maven/blob/main/DefaultRepositorySystemSessionFactory.java), the constant `MAVEN_RESOLVER_TRANSPORT_WAGON` defines this value as `"wagon"`:

```java
public static final String MAVEN_RESOLVER_TRANSPORT_WAGON = "wagon";

```

*Source:* [`impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java) (lines 82-86)

When this value is active, Maven prioritizes the `WagonTransporterFactory` using the priority key `"aether.priority.WagonTransporterFactory"` to ensure it handles all repository transport requests.

## Parsing Server Configuration from settings.xml

Before establishing connections, Maven reads the `<servers>` section of your *settings.xml* (or the file specified via `-s`). For each `<server>` element, the `DefaultRepositorySystemSessionFactory` extracts the configuration XML—specifically excluding the legacy `<wagonProvider>` element—and converts it into a Plexus configuration object.

The logic, found in [`DefaultRepositorySystemSessionFactory.java`](https://github.com/apache/maven/blob/main/DefaultRepositorySystemSessionFactory.java), stores this configuration under a specific property key:

```java
// Lines 22-38 (excerpt)
PlexusConfiguration config = XmlPlexusConfiguration.toPlexusConfiguration(dom);
configProps.put("aether.transport.wagon.config." + server.getId(), config);

```

*Source:* [`impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java)

This mapping ensures that when Aether later connects to a repository with a matching `<id>`, the `WagonTransporter` retrieves the corresponding `PlexusConfiguration` containing timeouts, HTTP headers, and authentication details.

## Building the Aether Repository Session

The `configProps` map containing the Wagon configurations is injected into the `RepositorySystem` session during initialization. The `WagonTransporterFactory` checks for the priority key to activate itself:

```java
private static final String WAGON_TRANSPORTER_PRIORITY_KEY = "aether.priority.WagonTransporterFactory";

```

Once active, the factory creates a `WagonTransporter` instance for each repository operation, passing the server-specific configuration properties retrieved from the session context.

*Source:* [`impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java) (lines 100-101)

## Resolving Wagon Implementations by Protocol

The `WagonTransporter` does not implement network protocols directly. Instead, it delegates to the **WagonManager** (located in the compatibility module) to obtain a concrete `Wagon` implementation based on the repository protocol (e.g., `http`, `https`, `scp`, `file`).

The `WagonManager` interface provides the lookup method:

```java
Wagon getWagon(String protocol) throws UnsupportedProtocolException;

```

*Source:* [`compat/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonManager.java`](https://github.com/apache/maven/blob/main/compat/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonManager.java) (lines 39-44)

Concrete implementations reside in `org.apache.maven.wagon.providers.*` and are registered as Plexus components with hints matching their protocol. For example, the SCP external provider declares itself as:

```java
@Component(role = org.apache.maven.wagon.Wagon.class,
           hint = "scpexe",
           instantiationStrategy = "per-lookup")
public class ScpExternalWagon extends AbstractWagon { … }

```

*Source:* [`its/core-it-support/core-it-wagon/src/main/java/org/apache/maven/wagon/providers/ssh/external/ScpExternalWagon.java`](https://github.com/apache/maven/blob/main/its/core-it-support/core-it-wagon/src/main/java/org/apache/maven/wagon/providers/ssh/external/ScpExternalWagon.java)

## Executing Repository Operations

Once Maven retrieves the appropriate `Wagon` instance, Aether uses it to perform actual I/O operations including artifact downloads, uploads, and checksum verification. The Wagon implementation respects the configuration parsed earlier, applying `<httpHeaders>`, `<connectTimeout>`, and `<requestTimeout>` values to each connection.

If the transport is not explicitly forced to Wagon, Maven automatically selects the highest-priority available transporter—typically the native Apache HttpClient implementation—falling back to Wagon only when specified or when the default is unavailable.

## Practical Configuration Examples

### Activating Wagon from the Command Line

```bash
mvn clean verify -Dmaven.resolver.transport=wagon

```

### Configuring Server-Specific Wagon Properties

Add this to your `$HOME/.m2/settings.xml` to customize HTTP behavior for a specific repository:

```xml
<settings>
  <servers>
    <server>
      <id>my-secure-repo</id>
      <username>deployer</username>
      <password>${server.password}</password>
      <configuration>
        <httpHeaders>
          <property>
            <name>User-Agent</name>
            <value>CorporateMaven/1.0</value>
          </property>
        </httpHeaders>
        <connectTimeout>5000</connectTimeout>
        <requestTimeout>30000</requestTimeout>
      </configuration>
    </server>
  </servers>
</settings>

```

### Referencing the Configured Server in Your Project

Ensure your project's *pom.xml* references the same ID used in *settings.xml*:

```xml
<project>
  <distributionManagement>
    <repository>
      <id>my-secure-repo</id>
      <url>https://nexus.internal.company.com/repository/maven-releases/</url>
    </repository>
  </distributionManagement>
</project>

```

When the build runs with `-Dmaven.resolver.transport=wagon`, Maven binds the server configuration to the Wagon transporter using the `aether.transport.wagon.config.my-secure-repo` property key.

## Summary

- **Activation**: Set `-Dmaven.resolver.transport=wagon` or rely on the `MAVEN_RESOLVER_TRANSPORT_WAGON` constant to enable Wagon mode.
- **Configuration Parsing**: [`DefaultRepositorySystemSessionFactory.java`](https://github.com/apache/maven/blob/main/DefaultRepositorySystemSessionFactory.java) converts `<server>` XML from *settings.xml* into `PlexusConfiguration` objects stored under `aether.transport.wagon.config.<serverId>`.
- **Transport Factory**: The `WagonTransporterFactory` reads these properties and constructs transporters when the priority key `"aether.priority.WagonTransporterFactory"` is active.
- **Protocol Resolution**: `WagonManager.getWagon(String protocol)` provides concrete implementations (such as `ScpExternalWagon`) based on component hints.
- **Execution**: The selected Wagon instance handles all network I/O, respecting timeouts and headers defined in the server configuration.

## Frequently Asked Questions

### How do I force Maven to use Wagon instead of the default HttpClient?

Pass the system property `-Dmaven.resolver.transport=wagon` on the command line. Alternatively, set the property in `MAVEN_OPTS` or configure it in your CI environment. Without this flag, Maven 4 typically defaults to the native Apache HttpClient transporter for improved performance.

### Where does Maven store the Wagon configuration from settings.xml?

Maven stores the raw XML configuration from each `<server>` element as a `PlexusConfiguration` object in the Aether session's configuration properties map. The key follows the pattern `aether.transport.wagon.config.<serverId>`, as implemented in [`DefaultRepositorySystemSessionFactory.java`](https://github.com/apache/maven/blob/main/DefaultRepositorySystemSessionFactory.java) lines 22-38.

### How does Maven select which Wagon implementation to use for a specific protocol?

The `WagonTransporter` delegates to `WagonManager.getWagon(String protocol)`, which looks up a Plexus component with the role `org.apache.maven.wagon.Wagon` and a hint matching the protocol string (e.g., `"http"`, `"scp"`, `"file"`). Implementations like `ScpExternalWagon` register themselves with the `@Component` annotation specifying their supported protocol hint.

### Is Wagon still the default transport in Maven 4?

No. Modern Maven versions prioritize the `apache` transport (using HttpClient) or the `native` transport by default. Wagon serves as a legacy-compatible alternative that you must explicitly enable via `maven.resolver.transport=wagon`, or it is used automatically only if other transports are unavailable in the classpath.