How Maven Configures and Uses Wagon for Repository Transport

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:

mvn clean deploy -Dmaven.resolver.transport=wagon

According to the source code in DefaultRepositorySystemSessionFactory.java, the constant MAVEN_RESOLVER_TRANSPORT_WAGON defines this value as "wagon":

public static final String MAVEN_RESOLVER_TRANSPORT_WAGON = "wagon";

Source: 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, stores this configuration under a specific property key:

// 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

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:

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 (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:

Wagon getWagon(String protocol) throws UnsupportedProtocolException;

Source: 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:

@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

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

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:

<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:

<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 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →