# How Maven's Lifecycle Execution Works Internally: From Task Segments to Mojo Execution

> Understand Maven lifecycle execution internally. Learn how goals become task segments, the reactor graph builds projects, and Mojos execute via a coordinated pipeline.

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

---

**Maven's lifecycle execution converts command-line goals into ordered task segments, resolves a project build list using the reactor graph, and delegates to a Builder that executes Mojo instances through a coordinated pipeline of `LifecycleStarter`, `LifecycleModuleBuilder`, and `MojoExecutor`.**

Maven's build lifecycle is orchestrated by a sophisticated internal engine within the `apache/maven` repository that transforms declarative POM configurations into concrete plugin executions. Understanding how Maven's lifecycle execution works internally reveals the modular architecture that supports both single-threaded and parallel builds across multi-module projects.

## The Entry Point: DefaultLifecycleStarter

The lifecycle execution begins when `MavenCli` creates a `MavenSession` from command-line arguments and delegates to `LifecycleStarter`. The default implementation in `DefaultLifecycleStarter` ([source](https://github.com/apache/maven/blob/master/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleStarter.java)) serves as the primary orchestrator.

Before processing begins, `DefaultLifecycleStarter` performs session validation. It checks `requiresProject` to ensure a POM is present when needed, throwing `MissingProjectException` or `NoGoalSpecifiedException` for malformed invocations. Once validated, the starter initiates the task segmentation process.

## Task Segmentation and Reactor Ordering

Maven analyzes command-line goals (e.g., `clean install`) through `LifecycleTaskSegmentCalculator.calculateTaskSegments(session)`. This splits goals into **task segments**—logical groupings representing lifecycle phases that execute together. The result is a `List<TaskSegment>` that defines the batch boundaries for the build.

Next, `BuildListCalculator` combines these task segments with the reactor's dependency graph to produce a `ProjectBuildList`. This ordered collection of `ProjectSegment` instances ([source](https://github.com/apache/maven/blob/master/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuildList.java)) determines which projects in a multi-module build execute for each task segment, respecting inter-module dependencies.

## Builder Selection and Concurrency

Maven supports multiple concurrency models through the `Builder` interface. The implementation selection depends on `session.getRequest().getBuilderId()`, populated via Guice dependency injection:

- **`SingleThreadedBuilder`**: The default serial builder ([source](https://github.com/apache/maven/blob/master/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/singlethreaded/SingleThreadedBuilder.java)) that processes projects sequentially.
- **`MultiThreadedBuilder`**: The parallel builder activated with the `-T` flag for concurrent module builds.

Before execution begins, the system creates a `ReactorContext` ([source](https://github.com/apache/maven/blob/master/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java)) to hold reactor-wide state. This includes the original class loader, the accumulating `MavenExecutionResult`, and a `ReactorBuildStatus` that tracks failures, halts, and blacklisted projects.

## Project Build Execution and Plan Resolution

The selected `Builder` iterates over `TaskSegment`s and their associated `ProjectSegment`s. For each project, it invokes `LifecycleModuleBuilder.buildProject()` ([source](https://github.com/apache/maven/blob/master/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java)).

Inside this method, `BuilderCommon` resolves a `MavenExecutionPlan` ([source](https://github.com/apache/maven/blob/master/api/maven-api/src/main/java/org/apache/maven/lifecycle/MavenExecutionPlan.java)) for the current project and task segment. This plan is a structured list of `MojoExecution` objects representing the specific lifecycle phases and plugin goals that must run.

```java
// Excerpt from SingleThreadedBuilder showing the core execution loop
for (TaskSegment taskSegment : taskSegments) {
    for (ProjectSegment projectBuild : projectBuilds.getByTaskSegment(taskSegment)) {
        lifecycleModuleBuilder.buildProject(session, reactorContext,
                                             projectBuild.getProject(), taskSegment);
        if (reactorBuildStatus.isHalted()) {
            break; // stop further builds on failure
        }
    }
}

```

## Mojo Execution and Event Publishing

The `MojoExecutor` ([source](https://github.com/apache/maven/blob/master/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java)) receives the `MavenExecutionPlan` and executes each `MojoExecution` in order. This handles plugin resolution, parameter injection, and lifecycle callbacks for individual goals.

Throughout the build, `ExecutionEventCatapult` ([source](https://github.com/apache/maven/blob/master/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionEventCatapult.java)) publishes events including `SessionStarted`, `ProjectStarted`, `ProjectSucceeded`, and `SessionEnded`. These events allow listeners such as console loggers and CI plugins to react to build progress.

After each project completes, `LifecycleModuleBuilder` records a `BuildSuccess` (or propagates failures) into the `MavenExecutionResult`. When all task segments finish processing, `DefaultLifecycleStarter` fires the final `SessionEnded` event and returns control to the CLI.

```java
// Inspecting the resolved execution plan for debugging
MavenExecutionPlan plan = builderCommon.resolveBuildPlan(
        session, currentProject, taskSegment, new HashSet<>());
plan.getMojoExecutions().forEach(mojo -> {
    System.out.println("Will execute: " + mojo.getArtifactId() + ":" + mojo.getGoal());
});

```

## Programmatic Invocation

The same internal pipeline used by the CLI can be invoked programmatically:

```java
import org.apache.maven.execution.MavenSession;
import org.apache.maven.lifecycle.internal.DefaultLifecycleStarter;
import org.apache.maven.cli.MavenCli;
import org.codehaus.plexus.PlexusContainer;

public class MavenRunner {
    public static void main(String[] args) throws Exception {
        // args = ["clean", "install"]
        MavenCli cli = new MavenCli();
        PlexusContainer container = cli.getContainer();

        // Build a MavenSession from the CLI arguments
        MavenSession session = cli.initialize(args, null, null);

        // Retrieve the default lifecycle starter (bound by Guice)
        DefaultLifecycleStarter starter = container.lookup(DefaultLifecycleStarter.class);
        starter.execute(session);   // triggers the whole lifecycle flow
    }
}

```

## Summary

- **`DefaultLifecycleStarter`** serves as the primary entry point, validating the session and coordinating the build flow.
- **`LifecycleTaskSegmentCalculator`** splits command-line goals into executable task segments, while `BuildListCalculator` creates the ordered `ProjectBuildList` for multi-module reactors.
- **Builder selection** determines concurrency: `SingleThreadedBuilder` for serial execution or `MultiThreadedBuilder` for parallel builds.
- **`LifecycleModuleBuilder`** resolves the `MavenExecutionPlan` via `BuilderCommon`, converting lifecycle phases into concrete `MojoExecution` instances.
- **`MojoExecutor`** runs each plugin goal with full parameter injection, while `ExecutionEventCatapult` broadcasts lifecycle events to registered listeners.
- **Result aggregation** collects `BuildSuccess` entries into `MavenExecutionResult`, with `ReactorContext` maintaining state across the entire build.

## Frequently Asked Questions

### What is the difference between a TaskSegment and a ProjectBuildList in Maven?

A **TaskSegment** represents a logical grouping of lifecycle phases derived from command-line arguments (e.g., combining consecutive goals like `clean install`), while a **ProjectBuildList** is an ordered collection of `ProjectSegment` instances that maps each task segment to specific projects in the reactor. The TaskSegment defines *what* to execute, and the ProjectBuildList defines *which* projects execute it, respecting dependency ordering.

### How does Maven decide whether to use single-threaded or multi-threaded builders?

Maven selects the builder implementation based on the `builderId` property in the execution request, accessed via `session.getRequest().getBuilderId()`. This identifier maps to Guice-injected builder implementations: `singlethreaded` resolves to `SingleThreadedBuilder` (default), while configuration options like `-T` (threads) trigger the `MultiThreadedBuilder` for parallel execution across modules.

### What happens if a project build fails during the lifecycle execution?

When a build fails, the `ReactorBuildStatus` (maintained within `ReactorContext`) tracks the failure and can halt further execution. The `SingleThreadedBuilder` checks `reactorBuildStatus.isHalted()` after each project and breaks the loop to stop processing subsequent projects. Failures are recorded as `BuildFailure` entries in the `MavenExecutionResult`, which aggregates results for all projects in the reactor.

### Can plugins modify the MavenExecutionPlan during the build?

While the `MavenExecutionPlan` is resolved by `BuilderCommon` before Mojo execution begins, plugins can influence execution through Maven's lifecycle extension points and event listeners. However, direct modification of the execution plan after resolution requires careful interaction with the `LifecycleModuleBuilder` and is not part of the standard plugin API. The plan remains immutable during the `MojoExecutor` phase to ensure deterministic builds.