# How Maven Handles Workspace Resolution and Multi-Module Projects: Inside the Reactor Architecture

> Discover how Maven handles workspace resolution and multi-module projects. Learn about the reactor architecture for efficient dependency management without intermediate builds.

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

---

**Maven handles workspace resolution and multi-module projects by treating the build as a reactor—an in-memory collection of all modules that allows dependencies to be resolved directly from source without requiring intermediate installation to the local repository.**

The `apache/maven` source code implements this through a sophisticated workspace reader infrastructure that checks the reactor before consulting external repositories. When you build a multi-module project, Maven constructs a `MavenSession` containing all projects, sorts them according to dependency relationships, and uses a `ReactorReader` to satisfy inter-module dependencies immediately.

## Understanding the Maven Reactor

### What Is the Reactor?

The reactor is Maven's internal representation of a multi-module build. When Maven starts, it reads the top-level [`pom.xml`](https://github.com/apache/maven/blob/main/pom.xml) and instantiates all declared modules as `MavenProject` objects, storing them in the current `MavenSession`. You can access this collection via `MavenSession#getAllProjects()`, which returns the sorted list of projects that constitute the build.

### Reactor Construction and Sorting

Before execution begins, Maven must determine the correct build order. The `DefaultProjectSorter` in [`impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectSorter.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectSorter.java) analyzes the dependency graph produced by `MavenProject#getDependencies()` and sorts modules so that upstream dependencies are built before downstream consumers. This ensures that when module B depends on module A, Maven compiles and packages A before attempting to resolve B's dependencies.

## Workspace Resolution Mechanics

Workspace resolution is the mechanism that allows Maven to resolve artifacts from the current build rather than the local repository. This is essential for multi-module development, where you want changes in one module to be immediately visible to others without running `mvn install`.

### The Workspace Reader Interface

At the core of this system is `MavenWorkspaceReader`, an extension of Eclipse Aether's `WorkspaceReader` interface defined in [`impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenWorkspaceReader.java`](https://github.com/apache/maven/blob/main/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/MavenWorkspaceReader.java). This interface provides methods to locate artifact descriptors and models within the current workspace.

### ReactorReader and In-Memory Lookup

The concrete implementation that knows about the current reactor is `ReactorReader`, located in [`impl/maven-core/src/main/java/org/apache/maven/ReactorReader.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/ReactorReader.java). When Maven resolves a dependency, it queries the `ReactorReader` via `findModel(Artifact)`. If the requested artifact belongs to a project in the current `MavenSession`, the reader returns the in-memory `Model` immediately, bypassing the local repository entirely.

This happens early in the resolution process. The `DefaultProjectBuilder` in [`impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java) invokes the workspace reader when parsing POMs or resolving parent projects, allowing parent-child relationships and sibling dependencies to be established directly from the reactor.

### Chained Resolution with MavenChainedWorkspaceReader

Maven supports multiple workspace readers through `MavenChainedWorkspaceReader` in [`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). This class chains the primary `ReactorReader` with additional readers supplied by IDEs or extensions. The chain is consulted in order: first the reactor, then IDE-specific readers, ensuring that in-project sources take precedence while allowing external workspaces to be resolved.

The workspace reader is injected into the execution via `MavenExecutionRequest#setWorkspaceReader` and stored in `DefaultMavenExecutionRequest` in [`impl/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java), then propagated to the `RepositorySystemSession` used throughout the build.

## Multi-Module Dependency Resolution

### Project Building and Inter-Module Dependencies

When `DefaultProjectBuilder` parses each module's POM, it resolves dependencies by querying the session's workspace reader. If a dependency points to another project in the reactor, the builder calls `MavenWorkspaceReader.findModel(Artifact)` and receives the model directly. This allows Maven to construct the dependency graph using the current source state rather than previously installed artifacts.

### Version Resolution Against the Reactor

The version resolution mechanism also consults the workspace reader. `DefaultVersionResolver` in [`impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultVersionResolver.java`](https://github.com/apache/maven/blob/main/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultVersionResolver.java) and `DefaultVersionRangeResolver` check the reactor when resolving specific versions or version ranges. This enables snapshot handling and version mediation to work correctly against the in-memory projects, ensuring that the latest source changes are always reflected in the dependency resolution.

Similarly, `DefaultArtifactDescriptorReader` in [`impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java`](https://github.com/apache/maven/blob/main/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java) uses the workspace reader to obtain artifact descriptors, allowing complete dependency metadata to be retrieved from the reactor without disk access.

## Partial Builds and Reactor Subsets

Maven supports building subsets of the reactor using command-line flags. When you run:

```bash
mvn -pl module-a,module-c -am clean install

```

Maven still constructs the full reactor but marks non-selected modules as inactive. The `-pl` flag selects specific modules, while `-am` (also-make) includes their upstream dependencies. The `ReactorReader` still provides models for all projects in the session, including inactive ones, ensuring that dependencies of selected modules can be satisfied even if those dependencies aren't being built in this execution.

## IDE Integration and Extended Workspace Readers

IDEs like IntelliJ IDEA and Eclipse provide their own workspace readers that integrate with Maven's resolution chain. These readers are added to the `MavenChainedWorkspaceReader` and consulted after the reactor reader. This allows IDEs to resolve artifacts that exist in the IDE workspace but may not be part of the current Maven reactor, while maintaining the priority of the current build's modules.

## Inspecting the Reactor Programmatically

You can access the reactor from within a Maven plugin to inspect the build structure. The following Mojo lists all projects in the current session:

```java
@Mojo(name = "list-reactor", threadSafe = true, requiresProject = false)
public class ListReactorMojo extends AbstractMojo {

    @Parameter(defaultValue = "${session}", readonly = true)
    private MavenSession session;

    public void execute() throws MojoExecutionException {
        getLog().info("Reactor size: " + session.getAllProjects().size());
        for (MavenProject p : session.getAllProjects()) {
            getLog().info("- " + p.getGroupId() + ":" + p.getArtifactId() + ":" + p.getVersion()
                           + "  (execution root: " + p.isExecutionRoot() + ")");
        }
    }
}

```

This plugin reads the `MavenSession` (which contains the sorted reactor via `DefaultMavenSession` in [`impl/maven-embedder/src/main/java/org/apache/maven/embeddable/DefaultMavenSession.java`](https://github.com/apache/maven/blob/main/impl/maven-embedder/src/main/java/org/apache/maven/embeddable/DefaultMavenSession.java)) and lists each project, indicating whether it is the execution root.

To manually check if an artifact resolves against the workspace reader (as Maven does internally):

```java
RepositorySystemSession repoSession = session.getRepositorySession();
WorkspaceReader wsReader = repoSession.getWorkspaceReader(); // actually a MavenChainedWorkspaceReader

Artifact dep = new DefaultArtifact("com.example:module-b:1.0-SNAPSHOT");
if (wsReader instanceof MavenWorkspaceReader mws) {
    Model model = mws.findModel(dep);
    if (model != null) {
        // The dependency is satisfied by a project inside the reactor.
        getLog().info("Found reactor project: " + model.getId());
    }
}

```

This mirrors the calls in `DefaultArtifactDescriptorReader` and `DefaultVersionResolver`, where the workspace reader is consulted before checking local or remote repositories.

## Summary

- **Maven treats multi-module builds as a reactor**: All modules are instantiated as `MavenProject` objects and stored in the `MavenSession`, accessible via `getAllProjects()`.
- **Workspace resolution prioritizes the reactor**: The `ReactorReader` implements `MavenWorkspaceReader` to provide in-memory models for dependencies that exist in the current build, eliminating the need for intermediate `mvn install` steps.
- **Sorting ensures correct build order**: `DefaultProjectSorter` orders projects based on the dependency graph from `MavenProject#getDependencies()`, ensuring upstream modules build first.
- **Chained readers support extensibility**: `MavenChainedWorkspaceReader` combines the reactor reader with IDE-specific readers, allowing flexible workspace resolution.
- **Partial builds maintain full reactor knowledge**: Even with `-pl` flags, Maven constructs the complete reactor, allowing dependencies to be resolved from inactive modules.

## Frequently Asked Questions

### How does Maven resolve dependencies between modules without installing them?

Maven uses the `ReactorReader` class in [`impl/maven-core/src/main/java/org/apache/maven/ReactorReader.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/ReactorReader.java) to implement `MavenWorkspaceReader`. When resolving a dependency, Maven consults this reader first; if the artifact belongs to a project in the current `MavenSession`, the reader returns the in-memory `Model` directly, bypassing the local repository entirely.

### What determines the build order in a multi-module Maven project?

The build order is determined by `DefaultProjectSorter` in [`impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectSorter.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectSorter.java). This component analyzes the dependency graph produced by `MavenProject#getDependencies()` and sorts modules so that each module is built only after its required upstream dependencies are compiled and packaged.

### Can I build only specific modules while still resolving dependencies from the rest of the project?

Yes. Using the `-pl` (projects list) flag combined with `-am` (also-make), you can build a subset of modules while Maven maintains the full reactor in memory. The `ReactorReader` still provides access to models for all projects in the session, including those not being built, ensuring that inter-module dependencies resolve correctly.

### How do IDEs integrate with Maven's workspace resolution?

IDEs provide custom implementations of `WorkspaceReader` that are chained with the `ReactorReader` via `MavenChainedWorkspaceReader` in [`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). These IDE-specific readers are consulted after the reactor reader, allowing the IDE to resolve artifacts from its own workspace while maintaining the priority of the current Maven build.