# Understanding Maven's Internal Architecture: Core Execution Model and Runtime Objects

> Explore Maven's internal architecture and its core execution model. Understand the five runtime objects: MavenExecutionRequest, MavenSession, MavenProject, MavenExecutionResult, and ReactorGraph that manage builds and dependenc...

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

---

**Apache Maven's internal architecture implements a model → build → execution pipeline through five core runtime objects—`MavenExecutionRequest`, `MavenSession`, `MavenProject`, `MavenExecutionResult`, and `ReactorGraph`—that orchestrate CLI configuration, project resolution, lifecycle execution, and dependency management.**

The Apache Maven source code (`apache/maven`) reveals a tightly-coupled modular design where immutable data structures and thread-local contexts collaborate to transform user input into completed builds. Understanding Maven's internal architecture requires tracing how these central objects interact from bootstrap to result aggregation, managing everything from POM inheritance to plugin isolation.

## Core Runtime Objects

Maven's execution layer revolves around five primary concepts that hold state during the build lifecycle.

### MavenExecutionRequest: The Configuration Holder

The `MavenExecutionRequest` class serves as a mutable data aggregator that captures all command-line options, system properties, profiles, and repository settings before execution begins. Defined in [`impl/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java), this object translates CLI arguments into structured fields including goals, offline mode flags, and base directory paths.

### MavenSession: The Build Context

`MavenSession` acts as the central runtime object that persists for the entire build duration. Stored in [`impl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java), it holds the `MavenExecutionRequest`, the `RepositorySystemSession` (Aether resolver), the ordered list of reactor projects, and thread-local state for the current project. The session maintains two critical project lists: the sorted `projects` for execution order and `allProjects` for aggregation operations.

### MavenProject: The Runtime POM Representation

After model inheritance and interpolation, `MavenProject` provides the runtime view of a single POM. Located in [`impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java), this class exposes resolved artifacts, source roots (`SourceRoot`), dependencies, and plugin descriptors. It preserves the original model (`originalModel`) while adding runtime-only data such as resolved classpath elements.

### MavenExecutionResult: The Build Outcome

`MavenExecutionResult` produces an immutable snapshot of the completed build. Implemented in [`impl/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java), it encapsulates the final `MavenSession`, accumulated exceptions, and the list of collected projects returned to the CLI layer.

### ReactorGraph: Module Visualization

The `ReactorGraph` utility generates DOT/SVG representations of module dependencies. Found in [`src/graph/ReactorGraph.java`](https://github.com/apache/maven/blob/main/src/graph/ReactorGraph.java), this visualization tool clusters artifacts by logical groups—such as Maven API, implementation, and resolver components—helping developers understand the dependency landscape of multi-module builds.

## The Build Execution Pipeline

Maven's architecture follows a strict seven-phase pipeline that transforms user input into build results.

1. **Bootstrapping** – The CLI (`org.apache.maven.Maven`) instantiates a `MavenExecutionRequest` and populates it with command-line arguments, system properties, and profile activations.

2. **Session creation** – The request initializes a `MavenSession` containing the `RepositorySystemSession` and a thread-local `MavenProject` pointing to the execution root.

3. **Project building** – The `ProjectBuilder` reads each [`pom.xml`](https://github.com/apache/maven/blob/main/pom.xml), resolves parent POMs, applies profile activation (`ProjectActivation`/`ProfileActivation`), and produces fully populated `MavenProject` instances with resolved `Artifact` objects.

4. **Reactor construction** – Maven sorts projects topologically using `ProjectDependencyGraph` and stores the ordered list in `MavenSession.projects`, maintaining the full list in `allProjects` for aggregation.

5. **Lifecycle execution** – The `DefaultLifecycleExecutor` walks lifecycle phases, resolves classpaths (using `getCompileClasspathElements` or the new `JavaPathType` API), and invokes plugins while storing contexts in `MavenSession.pluginContextsByProjectAndPluginKey`.

6. **Dependency resolution** – Aether (`org.eclipse.aether`) utilizes the `RepositorySystemSession` to download artifacts, apply checksum policies, and populate `MavenProject.artifacts` and `resolvedArtifacts`.

7. **Result aggregation** – `MavenExecutionResult` captures exceptions, the final session, and collected projects, returning this immutable structure to the CLI for success/failure reporting.

## Key Architectural Patterns

Several design patterns ensure thread safety and backward compatibility within Maven's architecture.

### Thread-Local Project Isolation

`MavenSession` uses a `ThreadLocal<MavenProject>` (`currentProject`) to maintain the "current" project without explicit parameter passing. This allows plugins to safely query context during parallel multi-module builds without cross-contamination.

### Plugin Context Isolation

The `pluginContextsByProjectAndPluginKey` map guarantees that plugin state remains isolated per project. This prevents state leakage between modules when the same plugin executes across different projects in the reactor.

### Immutable Model vs. Mutable Runtime

Maven maintains strict separation between the immutable `originalModel` (the parsed POM) and the mutable `MavenProject` runtime view. The runtime object adds resolved dependencies and source roots while preserving the original XML structure for reference.

### Compatibility Layers

Maven 4 introduces new APIs like `SourceRoot` while preserving deprecated methods such as `getCompileClasspathElements`. These legacy methods delegate to newer implementations, allowing existing plugins to function while migrating to immutable designs.

### Reactor Graph Visualization

The `ReactorGraph` tool parses DOT files from the graph plugin, applies clustering heuristics based on coordinate patterns (e.g., `org.apache.maven.api` vs. `org.apache.maven.impl`), and emits SVGs that reveal module coupling and API boundaries.

## Working with Maven's API

The following examples demonstrate programmatic interaction with Maven's core execution objects.

### Creating a Maven Execution Request

```java
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import java.util.Collections;

MavenExecutionRequest request = new DefaultMavenExecutionRequest();
request.setGoals(Collections.singletonList("install"));
request.addUserProperty("skipTests", "true");
request.setOffline(false);
request.setBaseDirectory(new File("/path/to/project"));

```

*Source*: `MavenExecutionRequest` setters in [`impl/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java) (lines 19-31).

### Building a Session from a Request

```java
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.MavenExecutionResult;
import org.eclipse.aether.RepositorySystemSession;

// Assume a populated request and RepositorySystemSession `repoSession`
MavenExecutionResult result = new MavenExecutionResult();
MavenSession session = new MavenSession(repoSession, request, result);

// Access ordered projects
List<MavenProject> sorted = session.getProjects();
MavenProject current = session.getCurrentProject();

```

*Source*: `MavenSession` constructor and accessors in [`impl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java) (lines 103-112, 141-149).

### Adding Source Roots (Maven 4 API)

```java
import org.apache.maven.project.MavenProject;
import org.apache.maven.api.ProjectScope;
import org.apache.maven.api.Language;
import java.nio.file.Path;

MavenProject project = ...;               // obtained from session
Path src = Path.of("src/main/java");

// Adds source only if it does not exist
project.addSourceRoot(ProjectScope.MAIN, Language.JAVA_FAMILY, src);

```

*Source*: `MavenProject.addSourceRoot(ProjectScope, Language, Path)` in [`impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java) (lines 447-452).

### Retrieving Compile Classpath (Legacy API)

```java
Set<Artifact> compileArtifacts = project.getArtifacts()
    .stream()
    .filter(a -> MavenProject.isCompilePathElement(a.getScope()))
    .collect(Collectors.toSet());

List<String> classpath = project.getCompileClasspathElements(); // deprecated

```

*Source*: `MavenProject.getCompileClasspathElements` in [`impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java) (lines 560-566).

### Visualizing the Reactor Graph

```bash

# Inside the Maven source tree

jbang src/graph/ReactorGraph.java

# Generates target/graph/high_level_graph.svg with clusters like "Maven API", "Sisu", etc.

```

*Source*: `ReactorGraph.main` in [`src/graph/ReactorGraph.java`](https://github.com/apache/maven/blob/main/src/graph/ReactorGraph.java) (lines 57-70).

## Summary

- **MavenExecutionRequest** acts as the mutable configuration holder that bridges CLI arguments to the internal execution model.
- **MavenSession** provides the thread-safe runtime context, using `ThreadLocal` to isolate the current project during multi-module builds.
- **MavenProject** represents the mutable runtime view of a POM, preserving the immutable `originalModel` while adding resolved artifacts and source roots.
- **ReactorGraph** offers visualization capabilities for understanding module dependencies through clustered SVG generation.
- The architecture maintains backward compatibility through delegation patterns, allowing Maven 4's immutable `SourceRoot` API to coexist with deprecated classpath methods.

## Frequently Asked Questions

### What is the difference between MavenExecutionRequest and MavenSession?

`MavenExecutionRequest` is a mutable data object that holds configuration before the build starts, while `MavenSession` is the persistent runtime context that lives throughout the build. The session contains the request, repository system session, and project state, whereas the request simply captures initial settings from the CLI and [`settings.xml`](https://github.com/apache/maven/blob/main/settings.xml).

### How does Maven isolate plugin state in multi-module builds?

Maven uses a `pluginContextsByProjectAndPluginKey` map within `MavenSession` to ensure plugin contexts remain isolated per project. This prevents state leakage when the same plugin executes across different modules in the reactor, maintaining thread safety during parallel builds.

### Why does Maven use ThreadLocal for the current project?

`MavenSession` stores the current project in a `ThreadLocal<MavenProject>` variable named `currentProject` to allow plugins to access build context without explicit parameter passing. This design enables safe concurrent execution while maintaining backward compatibility with plugins that expect to retrieve the project from the session implicitly.

### How has Maven 4 changed the source root API?

Maven 4 introduces the immutable `SourceRoot` API and deprecates methods like `getCompileClasspathElements` in favor of type-safe classpath access via `JavaPathType`. The `addSourceRoot(ProjectScope, Language, Path)` method now provides explicit scope and language binding, replacing the legacy string-based source root management while maintaining delegation compatibility for existing plugins.