Getting Started with Maven Build Cache Extension


Apache Maven 4 introduces a new feature - Build Cache Extension. This extension adds incremental build execution and caching capabilities that can noticeably improve the build performance.

The extension calculates a unique key representing the state of the project build at each execution. This key is built by analyzing the source code, the build flow, and plugin configurations. Once the key is built, the build output is stored against it and restored on subsequent executions if the project is unchanged. This can definitely remove the duplicate builds executions and improve the build times.

1. Prerequisite

Use of build cache extension requires, Apache Maven 4. Easiest way to get Maven 4 can be to use Apache Maven Wrapper with appropriate Maven 4 version.

Run following command to add/upgrade maven wrapper to use Apache Maven 4 -

shell.sh
 mvn wrapper:wrapper -Dmaven=4.0.0-alpha-3 (1)
1 At the time of writing this article, 4.0.0-alpha-3 was the latest available version.

Once you have wrapper initialized, you can run ./mvnw to invoke any maven goals in the project directory.

2. How to configure?

As this is a Maven build extension, there are two ways to add this to the project.

2.1. Using extensions.xml

Add extension dependency to {projectDir}/.mvn/extensions.xml file -

.mvn/extensions.xml
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 https://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
    <extension>
        <groupId>org.apache.maven.extensions</groupId>
        <artifactId>maven-build-cache-extension</artifactId>
        <version>1.0.0</version>
    </extension>
</extensions>

2.2. Using pom.xml

Add as a build extension in pom.xml -

pom.xml
    <!-- ... Other configurations of pom.xml -->
    <build>
        <extensions>
            <extension>
                <groupId>org.apache.maven.extensions</groupId>
                <artifactId>maven-build-cache-extension</artifactId>
                <version>1.0.0</version>
            </extension>
        </extensions>
    </build>

3. Cache in Action

With the dependency of cache extension added to the project, maven goal executions will now utilize the caching.

Running ./mvnw verify command on the project will show the cache usage. Let’s look at the maven output of this command on an example project -

maven.log
./mvnw verify
[INFO] Cache configuration is not available at configured path ~/maven-cache-example/.mvn/maven-build-cache-config.xml, cache is enabled with defaults  (1)
[INFO] Using XX hash algorithm for cache    (2)
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------------< com.github.manikmagar:maven-build-cache-example >------------------------------------
[INFO] Building maven-build-cache-example 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] ---------------------------------------------------------[ jar ]----------------------------------------------------------
[INFO] Going to calculate checksum for project [groupId=com.github.manikmagar, artifactId=maven-build-cache-example]    (3)
[INFO] Scanning plugins configurations to find input files. Probing is enabled, values will be checked for presence in file system
[INFO] Found 2 input files. Project dir processing: 5, plugins: 1 millis
[INFO] Project inputs calculated in 29 ms. XX checksum [a4f96e80300c2f22] calculated in 10 ms.  (4)
[INFO] Attempting to restore project com.github.manikmagar:maven-build-cache-example from build cache (5)
[INFO] Remote cache is incomplete or missing, trying local build for com.github.manikmagar:maven-build-cache-example
[INFO] Local build was not found by checksum a4f96e80300c2f22 for com.github.manikmagar:maven-build-cache-example   (5)
[INFO]
[INFO] --- resources:3.2.0:resources (default-resources) @ maven-build-cache-example ---    (6)
[INFO] Using 'UTF-8' encoding to copy filtered resources.
.... ### execution log continues until end ### ....
[INFO] --- jar:3.2.2:jar (default-jar) @ maven-build-cache-example ---
[INFO] Building jar: ~/maven-cache-example/target/maven-build-cache-example-1.0-SNAPSHOT.jar
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] Total time:  2.163 s (7)
[INFO] Finished at: 2023-01-29T08:42:08-05:00
[INFO] --------------------------------------------------------------------------------------------------------------------------
1 Looks for cache configuration file but since we don’t have one yet, it will run with default config
2 The default caching algorithm used - XX
3 Initializing checksum calculations for target artifact
4 Checksum calculated for the project input files
5 Attempt to restore any local cache against the checksum
6 In the absence of local cache, build continues with execution of subsequent build goals
7 Project build time when a cache miss

Let’s rerun ./mvnw verify on the project -

maven.log
.... ### Begining log is same with cache strategy ### ...

[INFO] ---------------------------------------------------------[ jar ]----------------------------------------------------------
[INFO] Going to calculate checksum for project [groupId=com.github.manikmagar, artifactId=maven-build-cache-example]
[INFO] Scanning plugins configurations to find input files. Probing is enabled, values will be checked for presence in file system
[INFO] Found 2 input files. Project dir processing: 8, plugins: 0 millis
[INFO] Project inputs calculated in 28 ms. XX checksum [a4f96e80300c2f22] calculated in 9 ms.   (1)
[INFO] Attempting to restore project com.github.manikmagar:maven-build-cache-example from build cache
[INFO] Remote cache is incomplete or missing, trying local build for com.github.manikmagar:maven-build-cache-example
[INFO] Local build found by checksum a4f96e80300c2f22   (2)
[INFO] Found cached build, restoring com.github.manikmagar:maven-build-cache-example from cache by checksum a4f96e80300c2f22 (3)
[INFO] Skipping plugin execution (cached): resources:resources   (3)
[INFO] Skipping plugin execution (cached): compiler:compile  (3)
[INFO] Skipping plugin execution (cached): resources:testResources  (3)
[INFO] Skipping plugin execution (cached): compiler:testCompile  (3)
[INFO] Skipping plugin execution (cached): surefire:test  (3)
[INFO] Skipping plugin execution (cached): jar:jar  (3)
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] Total time:  0.239 s (4)
[INFO] Finished at: 2023-01-29T09:12:40-05:00
[INFO] --------------------------------------------------------------------------------------------------------------------------
1 With no changes to the code, the extension calculates the same checksum
2 Cache hit - Local build is found from earlier execution
3 Restores the cached build and skips appropriate plugin executions
4 Project build time with cache hit
The project execution time with Cache-Hit reduced by ~89% of that with Cache-Miss.

3.1. Partial Restore for Incremental Builds

When running individual goals of build lifecycle, it is possible that cache may load partially until the last cached goal. Partial cache restore can still reduce the build time.

For example, when you run ./mvnw compile first that creates a build cache and then run ./mvnw package, the extension will load the cached build until compilation goal if nothing has change.

maven-partial.log
[INFO] Found cached build, restoring com.github.manikmagar:maven-build-cache-example from cache by checksum c8b3213be2fb697e
[INFO] Project com.github.manikmagar:maven-build-cache-example restored partially. Highest cached goal: compile, requested: package (1)
[INFO] Skipping plugin execution (cached): resources:resources  (2)
[INFO] Skipping plugin execution (cached): compiler:compile (2)
[INFO]
[INFO] --- resources:3.2.0:testResources (default-testResources) @ maven-build-cache-example --- (3)
[INFO] Using 'UTF-8' encoding to copy filtered resources.
1 Cache restored partially for goals higher than previous one
2 Build skipping previously cached executions
3 Build continues for higher executions

4. Customizing Cache Config

The default cache behavior uses some predefined Maven project conventions for discovering the source files. Sometimes project may have custom folder structure containing files that may affect the build output or some auto-generated files that must be excluded or plugin configuration adjustments for cache key computation.

It is possible to customize the Incremental Build and Cache configuration by adding .mvn/maven-build-cache-config.xml in the project.

Following is an example of custom config that -

  • Changes the Hash Algorithm to SHA-256 with hashAlgorithm

  • Retains the max last 3 builds in the cache with maxBuildsCached

  • Configures the input files with input

.mvn/maven-build-cache-config.xml
<cache xmlns="http://maven.apache.org/BUILD-CACHE-CONFIG/1.0.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/BUILD-CACHE-CONFIG/1.0.0 https://maven.apache.org/xsd/build-cache-config-1.0.0.xsd">
    <configuration>
        <enabled>true</enabled>
        <hashAlgorithm>SHA-256</hashAlgorithm>
        <validateXml>true</validateXml>
        <local>
            <maxBuildsCached>3</maxBuildsCached>
        </local>
        <projectVersioning adjustMetaInf="true"/>
    </configuration>
    <input>
        <global>
            <glob> {*.java,*.groovy,*.yaml,*.properties} </glob>
            <includes>
                <include>src/</include>
            </includes>
            <excludes>
                <exclude>temp.out</exclude>
            </excludes>
        </global>
    </input>
</cache>
Adding unnecessary rules and checks could reduce the performance as well as cache hit rate. Always test the behavior of your config to find the balance.

5. Disable cache

If for some reason, cache must be disabled, the there are two ways to do it.

Disable the cache using config file -

.mvn/maven-build-cache-config.xml
<cache>
  <configuration>
    <enabled>false</enabled>
  </configuration>
</cache>

The other way is to use command line argument -Dmaven.build.cache.enabled=false when executing any maven goal.

Disable cache from command line
./mvnw verify -Dmaven.build.cache.enabled=false

[INFO] Cache disabled by command line flag, project will be built fully and not cached
[INFO] Scanning for projects...

6. Conclusion

Maven Build Cache extension can definitely improve the build experience for maven projects. In this post, we looked at how to get started with using Build Cache in Maven. The maven-build-cache-example source is available on GitHub.

7. References

To learn more about Build Cache extension, check out following official documentation:

on twitter to get updates on new posts.

Stay updated!

On this blog, I post articles about different technologies like Java, MuleSoft, and much more.

You can get updates for new Posts in your email by subscribing to JavaStreets feed here -


Lives on Java Planet, Walks on Java Streets, Read/Writes in Java, JCP member, Jakarta EE enthusiast, MuleSoft Integration Architect, MuleSoft Community Ambassador, Open Source Contributor and Supporter, also writes at Unit Testers, A Family man!