# How Maven Artifact Transformation and Consumer POM Generation Works

> Discover how Maven artifact transformation and consumer POM generation simplify downstream dependencies by hiding internal build details. Learn the process and benefits.

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

---

**Maven generates a lightweight consumer POM by transforming the original project model, registering it as a classified artifact with the `consumer` classifier, and substituting it during install and deploy phases to hide internal build details from downstream projects.**

Apache Maven's artifact transformation and consumer POM generation creates a simplified, consumption-ready Project Object Model (POM) that downstream builds resolve instead of the full build POM. This mechanism, implemented in the `apache/maven` repository, strips build-specific metadata and optionally flattens dependency management to produce a cleaner transitive dependency graph. The process involves two primary components working in concert: the `ConsumerPomArtifactTransformer` which manages artifact registration, and the `DefaultConsumerPomBuilder` which handles the actual model transformation.

## Core Components of the Transformation Pipeline

The transformation pipeline splits responsibilities between artifact handling and model building. Understanding these classes is essential for debugging or extending Maven's consumer POM behavior.

### ConsumerPomArtifactTransformer

Located in [`impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java), this class serves as the entry point for the transformation process. It detects when the consumer POM feature is enabled via `Features.consumerPom(session.getConfigProperties())`, creates a temporary file named `consumer-*.pom`, and registers a new artifact with the **classifier `consumer`**. During the install and deploy phases, the `replacePom` method rewrites the artifact set so that the consumer POM replaces the normal POM, and optionally adds a second artifact with classifier **`build`** when the `deployBuildPom` flag is true.

### DefaultConsumerPomBuilder

Found in [`impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java), this class implements the core transformation logic. It handles three major concerns: **dependency flattening** (merging managed dependencies into direct ones), **model-version handling** (downgrading to Maven 3-compatible `modelVersion` 4.0.0 or preserving 4.2.0), and **pruning** (removing build-specific sections like mailing lists, issue management, and empty profiles).

## The Transformation Process Step-by-Step

Maven's artifact transformation follows a strict pipeline from feature detection to artifact substitution.

### Feature Detection and Activation

The process begins when `ConsumerPomArtifactTransformer.injectTransformedArtifacts` detects the consumer POM feature flag. When enabled, the method creates a temporary file and registers a `TransformedArtifact` with the `consumer` classifier. Temporary files are tracked in a thread-safe `CopyOnWriteArraySet` and cleaned up via the `@PreDestroy` hook (`doDeleteFiles`).

### Model Building and Path Selection

The `ConsumerPomArtifactTransformer.transform` method delegates to `PomBuilder.build`, which selects a transformation path based on packaging type:

- **POM packaging** (`pom`) → `buildPom` (calls `transformPom`)
- **BOM packaging** (`bom`) → `buildBom` or `buildBomWithoutFlatten`
- **Non-POM** (e.g., `jar`) → `buildNonPom` (calls `transformNonPom`)

### Dependency Flattening and Managed Dependencies

When `maven.consumer.pom.flatten=true`, the builder merges *dependencyManagement* entries into direct dependencies, applying version, scope, optional, and exclusion data. It also discards any managed entries that are not actually used (see lines 222-274 in [`DefaultConsumerPomBuilder.java`](https://github.com/apache/maven/blob/main/DefaultConsumerPomBuilder.java)). When flattening is disabled, the model is kept as-is, but BOM packaging still changes to `pom`.

### Model Version Handling and Compatibility

The builder handles model version compatibility through the `preserve.model.version` property. When mixins are present, Maven either throws an exception unless `preserve.model.version=true` or flattening is enabled, or it downgrades the model version to **4.0.0** for Maven 3 compatibility (lines 68-84). If preservation is requested, the newer 4.2.0 model version is maintained.

### Pruning Build-Specific Metadata

The `prune` helpers (lines 560-618) strip out consumption-irrelevant sections:

- Central repository entries (kept only if not `central`)
- Build-specific sections (mailing lists, issue management, SCM child-inheritance)
- Empty profiles (verified via `isEmpty`)
- Plugin repositories

### Artifact Substitution for Install and Deploy

After the transformed model is written, `ConsumerPomArtifactTransformer.replacePom` substitutes the original POM artifact with the consumer artifact (no classifier). If `deployBuildPom` is enabled, Maven attaches a second artifact with classifier **`build`** containing the original POM. This ensures repositories contain both the consumer-friendly POM and the full build POM when required.

## Configuration and Usage Examples

Enable the consumer POM feature and flattening from the command line:

```bash

# Activate consumer-POM generation and flattening

mvn clean install -DconsumerPom=true -Dmaven.consumer.pom.flatten=true

```

Inspect the generated consumer POM using the dependency tree plugin:

```bash

# View the consumer POM as a classified artifact

mvn dependency:tree -Dclassifier=consumer

```

Reference the consumer POM in downstream projects:

```xml
<dependency>
    <groupId>com.example</groupId>
    <artifactId>my-library</artifactId>
    <version>1.2.3</version>
    <!-- No classifier needed; Maven resolves the consumer POM automatically -->
</dependency>

```

## Summary

- **Maven artifact transformation** creates a lightweight consumer POM by processing the original model through `DefaultConsumerPomBuilder`.
- The **`ConsumerPomArtifactTransformer`** manages artifact registration, creates temporary `consumer-*.pom` files, and handles substitution during install/deploy.
- **Dependency flattening** merges managed dependencies into direct dependencies when `maven.consumer.pom.flatten=true`, reducing transitive dependency noise.
- **Model pruning** removes central repositories, mailing lists, issue management, and empty profiles to hide internal build details.
- The **classifier `consumer`** identifies the transformed artifact, while the optional **`build`** classifier preserves the original POM when `deployBuildPom` is enabled.
- Temporary files are managed in a thread-safe set and cleaned up via `@PreDestroy` hooks.

## Frequently Asked Questions

### What is the difference between the build POM and the consumer POM?

The **build POM** contains complete project metadata including build plugins, plugin repositories, mailing lists, and internal profiles required to build the project from source. The **consumer POM** is a transformed, lightweight version that strips these build-specific sections and optionally flattens dependency management, providing downstream projects with only the essential information needed for dependency resolution.

### How do I enable dependency flattening in the consumer POM?

Set the system property **`maven.consumer.pom.flatten=true`** when running Maven. This instructs `DefaultConsumerPomBuilder` to merge entries from `dependencyManagement` into direct dependencies, applying managed versions, scopes, and exclusions directly to the dependency list. This reduces the complexity of transitive dependency resolution for consumers.

### Why does Maven downgrade the model version to 4.0.0?

Maven downgrades to **`modelVersion` 4.0.0** to ensure compatibility with Maven 3 consumers when the project uses mixins or when `preserve.model.version` is not set to `true`. This occurs in `DefaultConsumerPomBuilder` (lines 68-84) to prevent Maven 3 installations from failing to parse newer 4.2.0 model features. Set `-Dpreserve.model.version=true` to retain the newer model version when all consumers use Maven 4.

### Can I deploy both the consumer POM and the original build POM?

Yes. When the **`deployBuildPom`** flag is enabled, `ConsumerPomArtifactTransformer.replacePom` registers two artifacts: the consumer POM (with no classifier) and the original build POM (with classifier **`build`**). This allows repository consumers to use the lightweight POM by default while still preserving the full build POM for tools that require complete project metadata.