@jnxplus/nx-maven
This plugin adds Maven multi-module capabilities to Nx workspace.
Quick Start
Get started with nx-maven in 5 steps:
# 1. Install the plugin
npm install --save-dev @jnxplus/nx-maven
# 2. Initialize workspace with Maven support (Java 17 + Spring Boot Parent POM)
nx generate @jnxplus/nx-maven:init --javaVersion 17 --dependencyManagement spring-boot-parent-pom
# 3. Generate a library
nx generate @jnxplus/nx-maven:library my-lib --framework spring-boot --directory libs
# 4. Generate an application that uses the library
nx generate @jnxplus/nx-maven:application my-app --framework spring-boot --projects my-lib --directory apps
# 5. Serve the application
nx serve my-app
Supported versions
@jnxplus/nx-maven | Nx | Spring Boot | Quarkus | Micronaut |
---|---|---|---|---|
1.x.x | >= 19 | 3.x.x | 3.x.x | 4.x.x |
0.x.x | >= 17 & <= 18 | 3.x.x | 3.x.x | 4.x.x |
Getting Started
0. Prerequisites
@jnxplus/nx-maven
requires a Java 17 or higher Runtime Environment and the current Long Term Support (LTS) version of node.js.
1. Install the plugin
In the Nx workspace root folder, run this command to install the plugin :
npm install --save-dev @jnxplus/nx-maven
2. Init workspace with Maven support
The following command adds Maven support (Maven wrapper and config files) to the workspace. This only needs to be performed once per workspace.
nx generate @jnxplus/nx-maven:init
You will be prompted for:
- Java version (default: none) - Options: none, 17, 21, or 25
- Dependency management strategy (default: none) - Options:
spring-boot-parent-pom
- Spring Boot Parent POMspring-boot-bom
- Spring Boot BOM (Bill of Materials)quarkus-bom
- Quarkus BOMmicronaut-parent-pom
- Micronaut Parent POMmicronaut-bom
- Micronaut BOMnone
- Configure manually later in a parent project (for advanced use cases)
Additional options:
--mavenRootDirectory
- Subdirectory for Maven files (default: workspace root). See Maven Root Directory section.--aggregatorProjectGroupId
- GroupId for root aggregator project (default: com.example)--aggregatorProjectName
- Name for root aggregator project (default: root-aggregator-project)--aggregatorProjectVersion
- Version for root aggregator project (default: 0.0.1-SNAPSHOT)--localRepoRelativePath
- Path to Maven local repository where dependencies are stored, relative to mavenRootDirectory (default: .m2/repository). Must be a subfolder within the workspace so Nx can cache and restore dependencies between builds--skipWrapper
- Skip generating Maven wrapper (default: false)--formatter
- Code formatter to use: prettier or none (default: prettier)
Important: Maven Root Directory
By default, Maven files (wrapper, config, and projects) are placed at the workspace root. However, you can specify a subdirectory using the --mavenRootDirectory
option:
nx generate @jnxplus/nx-maven:init --mavenRootDirectory maven
This creates the following structure:
workspace-root/
├── maven/ # Maven root directory
│ ├── .mvn/ # Maven wrapper config
│ ├── mvnw, mvnw.cmd # Maven wrapper scripts
│ ├── pom.xml # Root aggregator POM
│ ├── .m2/repository/ # Local Maven repository
│ └── my-app/ # Your projects
│ └── pom.xml
├── apps/ # Other Nx apps (non-Maven)
├── libs/ # Other Nx libs (non-Maven)
└── package.json
When to use mavenRootDirectory
:
- ✅ Monorepo organization - Keep Maven projects isolated in their own directory
- ✅ Better Nx caching - Separating Maven files improves Nx cache calculations and project graph performance
When to skip mavenRootDirectory
(use root):
- ✅ Simpler structure - Fewer nested directories
- ✅ Hybrid workspaces - Mix Maven projects with other technologies (Node.js, Python, etc.) at the root level
Note: Once set during init, the mavenRootDirectory
should remain consistent for all Maven projects in the workspace.
3. Generate a parent project (optional)
Parent projects help organize your applications and libraries with shared dependency management. Use parent projects when you need custom dependency management, want to organize projects into logical groups, or need to support multiple frameworks in your workspace.
nx generate @jnxplus/nx-maven:parent-project my-parent-project
Key options:
--javaVersion
- Java version (17, 21, 25, or none)--dependencyManagement
- Dependency management strategy (same options as init)--language
- Language for sub-projects: java, kotlin, or java-kotlin--directory
- Directory where the project will be created (default:libs
)--parentProject
- Parent project to inherit from (for nested parent projects)--aggregatorProject
- Aggregator project that manages a group of submodules
4. Generate applications and libraries
Generate an application
nx generate @jnxplus/nx-maven:application my-app
Key options:
--framework
- Framework to use: spring-boot, quarkus, micronaut, or none--language
- Language: java or kotlin (default: java)--parentProject
- Parent project to use (uses root aggregator project if not specified)--port
- Server port for the application--packaging
- Packaging type: jar or war (default: jar)--minimal
- Generate minimal application without starter code--groupId
- Maven groupId (default: com.example)--projectVersion
- Maven version (default: 0.0.1-SNAPSHOT)--directory
- Directory where the project will be created (default:apps
, e.g.,backend
creates atbackend/my-app
,apps/backend
creates atapps/backend/my-app
)--simpleName
- Don't include the directory in the project name (default: true)--simplePackageName
- Don't include the directory in the package name (default: true)--tags
- Tags for the project (comma-separated)
Generate a library
nx generate @jnxplus/nx-maven:library my-lib
Key options:
--framework
- Framework to use: spring-boot, quarkus, micronaut, or none--language
- Language: java or kotlin (default: java)--parentProject
- Parent project to use (uses root aggregator project if not specified)--projects
- Projects that will use this library (comma-separated)--skipStarterCode
- Skip generating starter code--groupId
- Maven groupId (default: com.example)--projectVersion
- Maven version (default: 0.0.1-SNAPSHOT)--directory
- Directory where the project will be created (default:libs
, e.g.,backend
creates atbackend/my-lib
,libs/backend
creates atlibs/backend/my-lib
)--simpleName
- Don't include the directory in the project name (default: true)--simplePackageName
- Don't include the directory in the package name (default: true)--tags
- Tags for the project (comma-separated)
Example with directory:
# Creates project at: backend/my-lib
# Project name (with simpleName=true): my-lib
# Package name (with simplePackageName=true): com.example.mylib
nx generate @jnxplus/nx-maven:library my-lib --directory backend
# Creates project at: backend/my-lib
# Project name (with simpleName=false): backend-my-lib
# Package name (with simplePackageName=false): com.example.backend.mylib
nx generate @jnxplus/nx-maven:library my-lib --directory backend --simpleName false --simplePackageName false
5. Common tasks
Action | Command |
---|---|
Build a project | nx build my-project |
Serve an application | nx serve my-app |
Test a project | nx test my-project |
Build a Docker image | nx build-image my-app |
Run custom Maven task | nx run-task my-project --task="clean install" |
Format a Java project | nx format --projects my-project |
Visualize project's dependency graph | nx graph |
6. Executors
nx-maven primarily uses the run-task
executor for all Maven operations. Most targets (build, test, serve, etc.) internally use run-task
to execute Maven commands.
run-task
Execute arbitrary Maven tasks on a project:
nx run-task my-project --task="clean install"
Options:
--task
(required) - Maven task(s) to execute. Can be a string or array of strings--outputDirLocalRepo
- Sub-directory in Maven local repository where artifacts from install phase will be placed--skipProject
- Skip specifying the project with-pl :project
flag--cwd
- Working directory for the command. Can be relative (to Maven root) or absolute--skipExecutor
- Skip executor execution (useful for conditional runs)
Examples:
# Single task
nx run-task my-app --task="clean package"
# Multiple tasks
nx run-task my-app --task="clean" --task="test" --task="package"
# With custom working directory
nx run-task my-app --task="compile" --cwd="custom-path"
# Skip project specification (run from Maven root)
nx run-task my-app --task="dependency:tree" --skipProject
quarkus-build-image
Build a Docker image for Quarkus applications:
nx build-image my-quarkus-app
Options:
--imageType
- Image type to build (default: jvm). Options: jvm, native, etc.--imageNamePrefix
- Image name prefix (default: quarkus)--imageNameSuffix
- Image name suffix
Examples:
# Build JVM image (default)
nx build-image my-quarkus-app
# Build native image
nx build-image my-quarkus-app --imageType=native
# Custom image name
nx build-image my-quarkus-app --imageNamePrefix=myapp --imageNameSuffix=latest
Note: For Spring Boot and Micronaut applications, the build-image target uses the run-task
executor with framework-specific commands:
- Spring Boot:
spring-boot:build-image
- Micronaut:
package -Dpackaging=docker
7. Plugin configuration
The init command configures the plugin in your nx.json
file. You can customize these options to fit your workspace needs.
Example configuration with default values:
{
"plugins": [
{
"plugin": "@jnxplus/nx-maven",
"options": {
"mavenRootDirectory": "nx-maven",
"localRepoRelativePath": ".m2/repository",
"buildTargetName": "build",
"testTargetName": "test",
"serveTargetName": "serve",
"integrationTestTargetName": "integration-test",
"buildImageTargetName": "build-image",
"skipAggregatorProjectLinking": false,
"skipProjectWithoutProjectJson": false
}
}
]
}
Available options:
mavenRootDirectory
- Subdirectory for Maven files (default: workspace root)localRepoRelativePath
- Path to Maven local repository (default: .m2/repository)buildTargetName
- Name for the build target (default: build)testTargetName
- Name for the test target (default: test)serveTargetName
- Name for the serve target (default: serve)integrationTestTargetName
- Name for the integration test target (default: integration-test)buildImageTargetName
- Name for the build image target (default: build-image)skipAggregatorProjectLinking
- Skip linking aggregator projects in the dependency graph. Enable this when aggregator projects only contain<modules>
declarations and all configuration is handled by parent projects. This improves Nx graph performance by reducing unnecessary dependency links. See Understanding parent projects vs aggregator projects for more details (default: false)skipProjectWithoutProjectJson
- Skip projects that don't have a project.json file (default: false)
8. Environment variables
You can customize nx-maven behavior using environment variables:
NX_MAVEN_CLI
Controls which Maven executable to use. Accepts: mvnw
, mvn
, or mvnd
.
Examples:
# Linux/macOS
export NX_MAVEN_CLI=mvn
nx build my-app
# Windows (PowerShell)
$env:NX_MAVEN_CLI='mvnd'
nx build my-app
# Windows (CMD)
set NX_MAVEN_CLI=mvn
nx build my-app
Default behavior (when not set):
- Uses
mvnw
(Maven wrapper) if it exists in the workspace - Falls back to
mvn
if wrapper doesn't exist
NX_MAVEN_CLI_OPTS
Pass additional arguments to Maven commands globally. Useful for CI/CD environments or consistent build settings.
Examples:
# Linux/macOS - disable transfer progress and enable verbose plugin validation
export NX_MAVEN_CLI_OPTS='--no-transfer-progress -Dmaven.plugin.validation=VERBOSE'
nx build my-app
# Windows (PowerShell) - run in batch mode
$env:NX_MAVEN_CLI_OPTS='--batch-mode'
nx test my-app
# Windows (CMD) - use offline mode
set NX_MAVEN_CLI_OPTS=--offline
nx build my-app
Common options:
--no-transfer-progress
- Disable download progress output (useful in CI)--batch-mode
- Run in non-interactive mode--offline
- Work offline (use cached dependencies only)-Dmaven.plugin.validation=VERBOSE
- Enable verbose plugin validation
Using a .env file
Create a .env
file in your workspace root to persist environment variables across sessions:
# .env file example
NX_MAVEN_CLI=mvnd
NX_MAVEN_CLI_OPTS=--no-transfer-progress --batch-mode
Note: The .env
file is automatically loaded by Nx. Variables defined here will be available to all nx-maven commands.
9. Visualizing the project graph
Nx provides a powerful project graph visualization to understand dependencies between your Maven projects:
nx graph
This opens an interactive view showing:
- Project dependencies - How your applications and libraries depend on each other
- Build order - Understanding which projects need to be built first
- Impact analysis - See what projects are affected by changes
Useful graph commands:
# View the full project graph
nx graph
# Show what's affected by changes
nx graph --affected
# Focus on a specific project and its dependencies
nx graph --focus=my-app
# Show only projects that depend on a specific project
nx graph --exclude=*,!tag:my-tag
How nx-maven builds the graph:
- Maven dependencies - Extracted from
pom.xml
files (<dependencies>
sections) - Profile dependencies - Dependencies defined within Maven profiles (
<profiles>
→<dependencies>
) - Plugin dependencies - Dependencies used by Maven plugins (
<build>
→<plugins>
→<dependencies>
). Note: Plugin dependencies can sometimes create cyclic dependency issues in the graph - Parent projects - Child projects depend on their parent (
<parent>
section) - Aggregator projects - Optional linking based on
<modules>
(controlled byskipAggregatorProjectLinking
)
Limitations:
- Profile dependencies are always included in the graph, regardless of whether the profile is active. This ensures the dependency graph remains consistent but may show dependencies that aren't used in your current build configuration.
Skipping projects:
You can exclude certain projects from the graph by setting skipProjectWithoutProjectJson: true
in your plugin configuration. This will skip any Maven projects that don't have a project.json
file, which is useful for ignoring Maven modules that aren't managed by Nx.
This integration allows Nx to:
- Run only affected tests when you make changes
- Build projects in the correct order
- Cache and distribute builds efficiently
10. Understanding parent projects vs aggregator projects
Why separate them? In nx-maven, keeping parent projects (configuration) separate from aggregator projects (module lists) improves Nx graph performance. Parent projects stay stable, aggregators only change when adding/removing projects.
Parent Project (--parentProject
)
What it does: Child projects inherit configuration and dependency management.
Contains:
- Dependency versions (
<dependencyManagement>
) - Plugin configurations
- Java version and properties
- Framework configurations (Spring Boot, Quarkus, Micronaut)
Example pom.xml
:
<parent>
<groupId>com.example</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
Aggregator Project (--aggregatorProject
)
What it does: Lists submodules for coordinated Maven builds.
Contains:
- Only
<modules>
declarations - No configuration or dependency management (use parent projects for that)
Example pom.xml
:
<modules>
<module>my-app</module>
<module>my-lib</module>
</modules>
Comparison
Aspect | Parent Project | Aggregator Project |
---|---|---|
Purpose | Configuration inheritance | Build coordination |
Direction | Bottom-up (child → parent) | Top-down (aggregator → modules) |
Changes when | Configuration updates | Projects added/removed |
Patterns
1. Default (root as parent and aggregator):
# Generate applications and libraries directly
# They inherit from root pom.xml and are listed there as modules
nx generate @jnxplus/nx-maven:application my-app --framework spring-boot
nx generate @jnxplus/nx-maven:library my-lib --framework spring-boot
All projects inherit configuration from and are aggregated by the root pom.xml
.
2. Separate parent and aggregator (recommended for advanced performance):
# Create parent for configuration
nx generate @jnxplus/nx-maven:parent-project shared-config --javaVersion 17
# Create aggregator (modules only, no config)
nx generate @jnxplus/nx-maven:parent-project apps-aggregator --javaVersion none --dependencyManagement none
# Projects inherit from parent, listed in aggregator
nx generate @jnxplus/nx-maven:application app1 --parentProject shared-config --aggregatorProject apps-aggregator
Tip: When using this pattern, enable skipAggregatorProjectLinking: true
in your nx.json
plugin options to optimize Nx graph performance since aggregators only contain module lists.
11. Project tagging
All projects generated by nx-maven are automatically tagged with nx-maven
. This allows you to:
Target Maven projects specifically:
# Run tests only on Maven projects
nx run-many -t test --projects=tag:nx-maven
# Build all Maven projects
nx run-many -t build --projects=tag:nx-maven
# Lint only Maven projects
nx run-many -t lint --projects=tag:nx-maven
Filter in the project graph:
# Show only Maven projects in the graph
nx graph --projects=tag:nx-maven
Custom tags:
You can add additional tags when generating projects using the --tags
option:
# Add custom tags
nx generate @jnxplus/nx-maven:application my-app --tags=backend,api
# Projects will have both auto and custom tags: ['nx-maven', 'backend', 'api']
12. Version management
nx-maven handles both static and property-based versions from pom.xml
files.
Static versions
<version>0.0.1-SNAPSHOT</version>
Static versions are used directly for dependency resolution and project graph construction.
Property-based versions
nx-maven supports Maven's CI-friendly versions using properties like ${revision}
, ${sha1}
, or ${changelist}
:
<version>${revision}</version>
<properties>
<revision>1.0.0-SNAPSHOT</revision>
</properties>
Version resolution process:
When nx-maven encounters a property-based version, it resolves it in this order:
- Project properties - Check
<properties>
in the current project'spom.xml
- Parent properties - Recursively check parent project properties
- Maven evaluation - As a fallback, use
mvn help:evaluate
(with performance warning)
Example with CI-friendly versions:
<!-- Parent pom.xml -->
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>${revision}</version>
<properties>
<revision>1.0.0-SNAPSHOT</revision>
</properties>
<!-- Child pom.xml -->
<parent>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>${revision}</version>
</parent>
<!-- Child inherits revision property from parent -->
Limitations:
- nx-maven resolves versions statically when building the project graph, not at runtime. If you override versions at build time (e.g.,
mvn clean install -Drevision=1.2.3
), the graph will still use the version defined in<properties>
.
Note: If nx-maven cannot resolve a version using properties (e.g., ${project.parent.version}
), it will fall back to mvn help:evaluate
, which is slower. If you encounter performance issues, please open an issue.
13. Other generators
Preset
The preset generator is used when creating a new Nx workspace with Maven support from scratch:
npx create-nx-workspace@latest my-workspace --preset=@jnxplus/nx-maven
This combines workspace creation and Maven initialization in one step.
Wrapper
Update or add the Maven wrapper to your workspace:
nx generate @jnxplus/nx-maven:wrapper
Options:
--skipGitignore
- Don't add Maven Wrapper to .gitignore (default: false)--skipFormat
- Skip formatting files (default: false)
Use this generator to:
- Update to the latest Maven wrapper version
- Add the wrapper if it was skipped during init (
--skipWrapper
) - Restore the wrapper if it was accidentally deleted
License
MIT © 2021-2025 Khalil LAGRIDA