# Core Implementation Details of Maven: How the Build Engine Executes Your Project

> Explore Maven's core implementation with DefaultMaven. Learn how it manages requests, builds project graphs, and executes lifecycles for your build.

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

---

**Maven's core implementation centers around `DefaultMaven`, which orchestrates the transformation of a `MavenExecutionRequest` into a `MavenExecutionResult` through session management, project graph construction, and lifecycle execution.**

Apache Maven is a declarative build automation tool used by millions of Java projects, and understanding the **core implementation details of Maven** reveals how it translates [`pom.xml`](https://github.com/apache/maven/blob/main/pom.xml) declarations into executed plugin goals. The heart of this system resides 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), which implements the public `Maven` interface and coordinates every build from validation to artifact resolution.

## Entry Point and Execution Flow

Every Maven build begins in the **`execute`** method of [`DefaultMaven.java`](https://github.com/apache/maven/blob/main/DefaultMaven.java). This method receives a `MavenExecutionRequest` populated from CLI options, [`settings.xml`](https://github.com/apache/maven/blob/main/settings.xml), and system properties, then delegates to a private `doExecute` method.

The `execute` method guarantees a result object is always returned by catching `OutOfMemoryError` and generic `RuntimeException` before wrapping them in a `MavenExecutionResult`. This design ensures that embedders and the CLI receive consistent feedback even when catastrophic failures occur.

## Session Initialization and Repository Setup

Inside `doExecute` (lines 199–210), Maven prepares the execution environment through a rigorous six-step process:

1. **Validate the local repository directory** via `validateLocalRepository(request)`
2. **Enter session scope** with `sessionScope.enter()` to enable injection of `@SessionScoped` components
3. **Build a `RepositorySystemSession`** (Aether session) via `RepositorySystemSessionFactory`, wrapped in a `CloseableSession` using `newCloseableSession(request, chainedWorkspaceReader)`
4. **Create the `MavenSession`** as the central data holder for the current build: `new MavenSession(closeableSession, request, result)`
5. **Seed the session scope** with the newly created objects via `sessionScope.seed(...)`
6. **Install the session into `LegacySupport`** using `legacySupport.setSession(session)` so legacy components can obtain it

This sequence establishes the **thread-local context** that all subsequent components rely on for dependency resolution and plugin execution.

## Project Discovery and the Reactor Graph

After session initialization, Maven discovers the multi-module project structure through the **`GraphBuilder`** interface. Located via dependency injection, the builder is invoked with `graphBuilder.build(session)` and returns a `Result<? extends ProjectDependencyGraph>`.

The graph builder performs two distinct passes:

- **Initial pass**: Builds a trimmed graph based on `--projects` arguments and reactor mode settings
- **Second pass**: Re-computes topology after lifecycle participants may have mutated project dependencies

If the result contains no errors, `DefaultMaven` populates the session's `projects`, `allProjects`, and `projectDependencyGraph` fields (lines 543–558) with the topologically sorted reactor.

## Extension Points via Lifecycle Participants

Maven extensions hook into the build lifecycle through **`AbstractMavenLifecycleParticipant`**. The `DefaultMaven` class fires three specific callbacks via `callListeners` (lines 371–382), which temporarily switches the thread’s context class loader to each participant’s class loader:

- **`afterSessionStart`**: Fires before any project is read
- **`afterProjectsRead`**: Fires after the reactor projects have been discovered
- **`afterSessionEnd`**: Fires after the build finishes

To implement a custom participant, extend `AbstractMavenLifecycleParticipant` and register it via [`META-INF/plexus/components.xml`](https://github.com/apache/maven/blob/main/META-INF/plexus/components.xml):

```java
public class MyParticipant extends AbstractMavenLifecycleParticipant {
    @Override
    public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
        System.out.println("Projects discovered:");
        session.getProjects().forEach(p -> System.out.println(" - " + p.getId()));
    }
}

```

## Workspace Resolution and Artifact Sources

Artifact resolution in Maven aggregates three distinct workspace readers through **`MavenChainedWorkspaceReader`**. The readers are queried in this order:

1. **Reactor reader**: Projects currently participating in the build (`lookup.lookup(WorkspaceReader.class, ReactorReader.HINT)`)
2. **Session-scoped readers**: IDE integrations or command-line supplied readers collected in `MavenChainedWorkspaceReader`
3. **Project-scoped readers**: Extensions defined in specific POMs via `getProjectScopedExtensionComponents`

The combined readers are stored back into the `MavenChainedWorkspaceReader` in the `setupWorkspaceReader` method (lines 337–352), enabling resolution of interim artifacts before they are installed to the local repository.

## Profile Validation and Prerequisites

Profile merging occurs in `getAllProfiles` (lines 511–539), which combines definitions from the POM hierarchy, [`settings.xml`](https://github.com/apache/maven/blob/main/settings.xml), and the **Super POM**. Required and optional profiles are then validated against this merged set through `validateRequiredProfiles` and `validateOptionalProfiles`.

Prerequisites defined in non-plugin projects trigger warnings via `validatePrerequisitesForNonMavenPluginProjects`, as version requirements are only enforced for Maven plugins.

## Lifecycle Execution

Once validation completes, the actual build logic delegates to **`LifecycleStarter`**:

```java
LifecycleStarter lifecycleStarter = lookup.lookupOptional(LifecycleStarter.class, request.getBuilderId())
        .orElseGet(() -> lookup.lookup(LifecycleStarter.class));
lifecycleStarter.execute(session);

```

Found under `org.apache.maven.lifecycle.internal`, `LifecycleStarter` walks through each project’s declared phases (e.g., `process-resources`, `compile`, `package`) and invokes the appropriate mojos. The starter handles parallelization strategies and ensures that reactor modules respect the topological order established by the graph builder.

## Error Handling and Build Resumption

When a `LifecycleExecutionException` occurs, Maven attempts to persist **resumption data** via `persistResumptionData`. This enables the `-r`/`--resume-from` feature in subsequent runs, allowing developers to restart failed multi-module builds from the point of failure.

All exceptions are collected in the `MavenExecutionResult`. When the request finishes, `LegacySupport` clears its session reference to prevent stale references in long-running embedder contexts.

## Summary

- **`DefaultMaven.execute`** serves as the single entry point that guarantees a `MavenExecutionResult` even during OutOfMemoryErrors
- **Session initialization** creates a `RepositorySystemSession` and `MavenSession` that provide the context for all dependency resolution
- **GraphBuilder** performs a two-pass analysis to determine project build order while respecting `--projects` filters
- **AbstractMavenLifecycleParticipant** provides three extension points for custom logic before, during, and after project discovery
- **MavenChainedWorkspaceReader** aggregates reactor, IDE, and project-scoped readers for flexible artifact resolution
- **LifecycleStarter** executes the actual mojo bindings after the reactor graph is validated
- **Build resumption** persists failure data to enable the `-r` resume feature

## Frequently Asked Questions

### How does Maven handle the transition from CLI arguments to executable build phases?

Maven populates a `MavenExecutionRequest` from CLI options and [`settings.xml`](https://github.com/apache/maven/blob/main/settings.xml), then passes it to `DefaultMaven.execute()`. This method constructs a `MavenSession`, discovers the reactor via `GraphBuilder`, and delegates to `LifecycleStarter` for phase execution. The entire flow transforms declarative configuration into ordered plugin invocations through the session and graph components.

### What is the purpose of AbstractMavenLifecycleParticipant in Maven's architecture?

**`AbstractMavenLifecycleParticipant`** is an extension point that allows plugins and extensions to intercept the build lifecycle at three specific points: after the session starts, after projects are read, and after the session ends. It is implemented by subclassing and registering via Plexus components, enabling custom validation, logging, or project modification before the lifecycle executes.

### How does Maven resolve artifacts from the current reactor before they are installed?

Maven uses **`MavenChainedWorkspaceReader`** to chain multiple workspace readers, including the **ReactorReader** for current projects, session-scoped readers for IDE integration, and project-scoped readers for extensions. This chain is queried before the local repository, allowing resolution of interim build artifacts during multi-module builds.

### Where does Maven store information to enable the resume from failure feature?

When a build fails with a `LifecycleExecutionException`, `DefaultMaven` calls `persistResumptionData` to store the current build state. This data is consumed by the `BuildResumptionAnalyzer` and `BuildResumptionDataRepository` to support the `-r`/`--resume-from` flag, allowing subsequent executions to skip successfully completed modules and restart from the failed point.