Declaration of source directories in Maven 4
By default, Maven compiles all *.java
files in the src/main/java
directory as the main Java code
and all *.java
files in the src/test/java
directory as the test Java code.
This is suitable for a project in a single Java module targeting a single Java release.
This page describes how to use different or additional directories in Maven 4.
The Maven 3 <sourceDirectory>
and <testSourceDirectory>
elements are deprecated
and should be replaced by the new <sources>
element introduced in Maven 4.
This new element allows multi-source, multi-release and multi-module projects,
as shown in sub-sections of this page.
Instead of:
<project>
<build>
<sourceDirectory>my-custom-dir/foo</sourceDirectory>
<testSourceDirectory>my-custom-dir/bar</testSourceDirectory>
</build>
</project>
One can write:
<project>
<build>
<sources>
<source>
<scope>main</scope> <!-- Can be omited as it is the default -->
<directory>my-custom-dir/foo</directory>
</source>
<source>
<scope>test</scope>
<directory>my-custom-dir/bar</directory>
</source>
</sources>
<build>
</project>
Note that the declaration of a <sources>
element replaces the default values.
If a <source>
element is defined for one of the main
or test
scopes, then a
<source>
element should generally be defined for the other scope
even if the latter use the default directory.
See the example in next sub-section.
Declaration of many source directories
External plugins such as build-helper-maven-plugin
are no longer needed
and should be replaced by the build-in <sources>
elements as shown below.
Note that the directories of the first and last <source>
elements are omitted
as their default values are src/main/java
and src/test/java
respectively.
<project>
<build>
<sources>
<source>
<scope>main</scope>
<!-- Default directory is src/main/java -->
</source>
<source>
<scope>main</scope> <!-- Can be omited as it is the default -->
<directory>src/extension/java</directory>
</source>
<source>
<scope>test</scope>
<!-- Default directory is src/test/java -->
</source>
</sources>
<build>
</project>
Multi-releases project
The new compiler plugin handles automatically multiple executions of javac
with different --release
option values
together with automatic adjustments of class-path, module-path and output directories for producing a multi-releases project.
Example:
<project>
<build>
<sources>
<source>
<targetVersion>17</targetVersion>
<!-- Default directory is src/main/java -->
</source>
<source>
<targetVersion>21</targetVersion>
<directory>src/main/java_21</directory>
</source>
<source>
<scope>test</scope>
<!-- Default directory is src/test/java -->
</source>
</sources>
</build>
</project>
Multi-module project
Maven 4 supports the Java module source hierarchy
with the canvas that as of October 2025, not all plugins have been updated yet.
Compared to multi Maven sub-project, using multi Java module in a single Maven sub-project has advantages such as
resolving compiler warnings in references to dependent modules (the converse of references to dependencies),
easier sharing of test code between modules in the Maven sub-project (no need for test-jar
),
and easier aggregated Javadoc for modules in the Maven sub-project.
See the modular projects page for more information.
For example, a Maven sub-project containing two Java modules named org.foo.bar.module1
and org.foo.bar.module2
can be declared with the following fragment in the pom.xml
file:
<build>
<sources>
<source>
<module>org.foo.bar.module1</module>
<!-- Default directory is src/org.foo.bar.module1/main/java -->
</source>
<source>
<module>org.foo.bar.module2</module>
<!-- Default directory is src/org.foo.bar.module2/main/java -->
</source>
<source>
<scope>test</scope>
<module>org.foo.bar.module1</module>
<!-- Default directory is src/org.foo.bar.module1/test/java -->
</source>
<source>
<scope>test</scope>
<module>org.foo.bar.module2</module>
<!-- Default directory is src/org.foo.bar.module2/test/java -->
</source>
</sources>
</build>
The default directory layout is then as below:
src
├─ org.foo.bar.module1
│ ├─ main
│ │ ├─ java
│ │ │ └─ org/foo/bar/**/*.java
│ └─ test
│ └─ java
│ └─ org/foo/bar/**/*Test.java
└─ org.foo.bar.module2
├─ main
│ └─ java
│ └─ org/foo/bar/**/*.java
└─ test
└─ java
└─ org/foo/bar/**/*Test.java
Current support
As of October 2025, only the Maven Compiler Plugin supports module source hierarchy. The following plugins need to be updated:
- Maven Surefire plugin
- Maven JAR plugin
- Maven Javadoc plugin
Include/exclude filters
The Maven 3 way to declare include/exclude filters is still supported,
but should be replaced by the <sources>
element when applicable.
Those two ways are not strictly equivalent:
- The Maven 4 way specifies filters independently for each source directory. These filters will be applied by all plugins that migrated to the Maven 4 API, not only the compiler plugin.
- Conversely, the Maven 3 way specifies filters which will be applied only by the compiler plugin. However, these filters apply to all source directories.
The following (Maven 3) specifies a filter applied on all source directories but only by the compiler plugin:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/Foo*.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
The following (Maven 4) specifies a filter applied only on the specified directories, but potentially used (when relevant) by all plugins upgraded to Maven 4:
<project>
<build>
<sources>
<source>
<directory>src/main/java</directory>
<excludes>
<exclude>**/Foo*.java</exclude>
</excludes>
</source>
<source>
<scope>test</scope>
<directory>src/test/java</directory>
</source>
</sources>
</build>
</project>