# How to Understand Maven's Core Implementation: A Complete Guide to the Build Lifecycle

> Understand Maven's core implementation by exploring its build lifecycle orchestration. Learn about Git, dependency graphs, and extension points for efficient build management.

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

---

**Maven's core implementation orchestrates builds through the `DefaultMaven` class, which validates the environment, creates a `MavenSession`, builds a project dependency graph via `GraphBuilder`, and executes the lifecycle through `LifecycleStarter`, with extension points provided by `AbstractMavenLifecycleParticipant`.**

Apache Maven's core is a sophisticated build orchestration engine that transforms POM files into executable build steps. To truly understand Maven's core implementation, you need to examine the interplay between session management, graph construction, and lifecycle execution as implemented in the `apache/maven` repository. This guide walks through the actual source code, showing how `DefaultMaven` coordinates the build process from CLI invocation to plugin execution.

## Core Architecture Components

Maven's architecture is built around a small set of high-level services that drive the **build lifecycle**. These components work together to transform execution requests into completed builds.

### The Maven Interface and DefaultMaven

The **`Maven`** interface in [`impl/maven-core/src/main/java/org/apache/maven/Maven.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/Maven.java) declares the single entry point `execute(MavenExecutionRequest)` that all clients call. The concrete implementation, **`DefaultMaven`** ([`impl/maven-core/src/main/java/org/apache/maven/DefaultMaven.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/DefaultMaven.java)), orchestrates the entire build process:

- Validates the local repository
- Creates a `RepositorySystemSession`
- Builds a `MavenSession`
- Runs lifecycle participants
- Constructs the project graph
- Starts the lifecycle execution

### MavenSession and Execution State

**`MavenSession`** ([`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)) holds the mutable state for a single build. It contains:
- The `MavenExecutionRequest` and `MavenExecutionResult`
- The current `MavenProject` and full project lists
- The `ProjectDependencyGraph`
- Plugin contexts
- The underlying Aether `RepositorySystemSession`

**`MavenExecutionRequest`** ([`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)) carries all CLI options, goals, profiles, and properties, while **`MavenExecutionResult`** ([`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)) collects the produced projects and any exceptions.

### GraphBuilder and ProjectDependencyGraph

The **`GraphBuilder`** ([`impl/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java)) resolves all POM relationships and produces a **`ProjectDependencyGraph`** that is topologically sorted. This determines the reactor build order.

### LifecycleStarter and Plugin Execution

**`LifecycleStarter`** ([`impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java)) runs the build after the graph is ready. It iterates over each project, creates `MojoExecution`s for the requested phases/goals, and delegates to the **`BuildPluginManager`** ([`impl/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java)).

The **`MavenPluginManager`** ([`impl/maven-core/src/main/java/org/apache/maven/plugin/MavenPluginManager.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/plugin/MavenPluginManager.java)) resolves plugin descriptors and creates plugin class realms.

### Extension Points with AbstractMavenLifecycleParticipant

**`AbstractMavenLifecycleParticipant`** ([`impl/maven-core/src/main/java/org/apache/maven/AbstractMavenLifecycleParticipant.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/AbstractMavenLifecycleParticipant.java)) provides hooks for core extensions at three points:
- `afterSessionStart`
- `afterProjectsRead`
- `afterSessionEnd`

### Workspace Resolution

**`MavenChainedWorkspaceReader`** ([`impl/maven-core/src/main/java/org/apache/maven/resolver/MavenChainedWorkspaceReader.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/resolver/MavenChainedWorkspaceReader.java)) chains the reactor reader, IDE reader, and any custom readers so that artifacts can be resolved from the current reactor, the IDE's workspace, or the local repository.

## Execution Flow in DefaultMaven

The entry point `DefaultMaven.execute(request)` (lines 44-65 in [`impl/maven-core/src/main/java/org/apache/maven/DefaultMaven.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/DefaultMaven.java)) delegates to `doExecute(request)`, which orchestrates the build through these distinct phases:

1. **Validate Local Repository** - `validateLocalRepository(request)` (lines 376-387) ensures the local repository exists and is writable.

2. **Create MavenSession** - `newCloseableSession(request, chainedWorkspaceReader)` instantiates the session (lines 162-176), capturing all build state including the Aether repository session.

3. **Enter Session Scope** - `sessionScope.enter()` (lines 112-119) makes `@SessionScoped` components injectable into lifecycle participants.

4. **Fire afterSessionStart** - `callListeners(..., AbstractMavenLifecycleParticipant::afterSessionStart)` (lines 274-282) notifies extensions that the session is ready.

5. **Add Reactor Workspace Reader** - `lookup(WorkspaceReader.class, ReactorReader.HINT)` (line 243) enables resolution of projects within the current reactor.

6. **Discover Projects** - `eventCatapult.fire(ProjectDiscoveryStarted, ...)` and `graphBuilder.build(session)` (lines 248-254) resolve all POMs and build the initial `ProjectDependencyGraph`.

7. **Set Project Map and Workspace Readers** - `setProjectMap(...)` (line 260) and `setupWorkspaceReader(...)` (lines 306-312) configure the session for the resolved projects.

8. **Fire afterProjectsRead** - Extensions can manipulate the model before the graph is re-sorted.

9. **Rebuild Graph** - A second call to `graphBuilder.build(session)` (lines 322-330) incorporates any changes made by participants.

10. **Validate Prerequisites and Profiles** - Methods `validatePrerequisitesForNonMavenPluginProjects`, `validateRequiredProfiles`, and `validateOptionalProfiles` (lines 360-410) ensure build requirements are met.

11. **Start Lifecycle** - `lookupOptional(LifecycleStarter.class, ...).execute(session)` (lines 388-393) begins the actual build execution.

12. **Persist Resumption Data** - If an exception occurs, `persistResumptionData(result, session)` (lines 417-426) saves state for build resumption.

13. **Fire afterSessionEnd** - Cleanup hook (lines 438-442) notifies extensions that the build is complete.

14. **Return Result** - The `MavenExecutionResult` contains the final list of projects, any exceptions, and the resume flag.

## Practical Code Examples

### Programmatically Executing a Maven Build

You can run Maven programmatically using the core API, mirroring the steps performed inside `DefaultMaven.doExecute`:

```java
import org.apache.maven.*;
import org.apache.maven.execution.*;
import org.apache.maven.api.services.*;
import org.apache.maven.internal.impl.DefaultSessionFactory;
import org.apache.maven.di.*;

public class MavenInvoker {
    public static void main(String[] args) throws Exception {
        // Build a simple execution request
        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
        request.setBaseDirectory(new File("."));
        request.setGoals(List.of("clean", "install"));
        request.setUserProperties(System.getProperties());
        request.setSystemProperties(System.getProperties());

        // Obtain the core Maven component (uses Maven's DI container)
        Maven maven = new DefaultMaven(
            new DefaultLookup(),                     // Lookup implementation
            new ExecutionEventCatapult(),            // Event dispatcher
            new LegacySupport(),                     // Legacy support (session holder)
            new SessionScope(),                      // Session scope manager
            new RepositorySystemSessionFactory(),    // Aether session factory
            new GraphBuilderImpl(),                  // Graph builder implementation
            new BuildResumptionAnalyzer(),
            new BuildResumptionDataRepository(),
            new SuperPomProvider(),
            new DefaultSessionFactory(),
            null                                     // No IDE WorkspaceReader
        );

        // Execute the build
        MavenExecutionResult result = maven.execute(request);

        // Inspect the result
        if (result.hasExceptions()) {
            result.getExceptions().forEach(Throwable::printStackTrace);
        } else {
            System.out.println("Build succeeded, projects built:");
            result.getTopologicallySortedProjects()
                  .forEach(p -> System.out.println("  - " + p.getId()));
        }
    }
}

```

*Key points*: This snippet demonstrates how to construct a request, obtain the core `Maven` implementation (normally wired by Maven's DI container), and run a build programmatically.

### Accessing the Reactor Graph

After execution, you can retrieve the `ProjectDependencyGraph` that the `GraphBuilder` produced:

```java
MavenExecutionResult result = maven.execute(request);
MavenSession session = ((DefaultMavenExecutionResult) result).getSession(); // cast to internal type
ProjectDependencyGraph graph = session.getProjectDependencyGraph();

System.out.println("Reactor order:");
graph.getSortedProjects().forEach(p -> System.out.println(p.getId()));

```

This demonstrates how to access the topologically sorted project list from the session.

### Creating a Custom Lifecycle Participant

Extend `AbstractMavenLifecycleParticipant` to intercept the build at extension points:

```java
package com.example;

import org.apache.maven.AbstractMavenLifecycleParticipant;
import org.apache.maven.execution.MavenSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyParticipant extends AbstractMavenLifecycleParticipant {
    private final Logger log = LoggerFactory.getLogger(getClass());

    @Override
    public void afterProjectsRead(MavenSession session) {
        log.info("Projects after reading: {}", session.getProjects().size());
        // Example: inject a dummy project property
        session.getAllProjects().forEach(p -> 
            p.getProperties().setProperty("myProp", "hello"));
    }
}

```

Register the participant via a core extension ([`META-INF/plexus/components.xml`](https://github.com/apache/maven/blob/main/META-INF/plexus/components.xml)). Maven invokes it at the three hook points: `afterSessionStart`, `afterProjectsRead`, and `afterSessionEnd`.

## Summary

Understanding Maven's core implementation requires tracing the execution flow through these key components:

- **`DefaultMaven`** orchestrates the entire build lifecycle from validation to completion
- **`MavenSession`** maintains mutable state including the project list and dependency graph
- **`GraphBuilder`** constructs the topologically sorted reactor graph before execution
- **`LifecycleStarter`** drives the actual plugin execution phase
- **`AbstractMavenLifecycleParticipant`** provides extension points for customizing the build process
- **`MavenChainedWorkspaceReader`** enables artifact resolution from the reactor, IDE, and local repository

The separation of concerns between session handling, graph construction, extension points, and plugin execution makes Maven's architecture both extensible and maintainable.

## Frequently Asked Questions

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

**`MavenExecutionRequest`** is an immutable configuration object that carries all CLI options, goals, profiles, and properties specified by the user. **`MavenSession`** is the mutable runtime state that holds the request, the resulting projects, the dependency graph, plugin contexts, and the Aether repository session. While the request defines what to build, the session tracks the actual build progress and outcomes.

### How does Maven determine the build order for multi-module projects?

Maven uses the **`GraphBuilder`** to construct a `ProjectDependencyGraph` by analyzing inter-module dependencies declared in the POM files. The graph is topologically sorted so that dependencies are built before the projects that depend on them. This graph is built twice during execution: once initially after project discovery, and again after `afterProjectsRead` extensions have potentially modified the project list (lines 322-330 in [`DefaultMaven.java`](https://github.com/apache/maven/blob/main/DefaultMaven.java)).

### What is the purpose of session scope in Maven's core?

Session scope (`SessionScope`) is a dependency injection mechanism that makes `@SessionScoped` components available throughout a single build execution. When `sessionScope.enter()` is called (line 112-119 in [`DefaultMaven.java`](https://github.com/apache/maven/blob/main/DefaultMaven.java)), the session becomes injectable into lifecycle participants and other components, ensuring that all parts of the build share the same execution context and state.

### How can I customize Maven's behavior without modifying the core?

Extend **`AbstractMavenLifecycleParticipant`** and register it as a core extension. This allows you to intercept the build at three specific points: after the session starts (`afterSessionStart`), after projects are read but before execution (`afterProjectsRead`), and after the session ends (`afterSessionEnd`). Common use cases include modifying project properties, injecting custom workspace readers, or implementing CI-friendly versioning schemes.