Parallel Maven Module Builds in Jenkins Declarative Pipeline: Avoiding Repository Contention and Executor Overload
Learn how to run independent Maven modules in parallel with Jenkins Declarative Pipeline while isolating local repositories, resolving dependencies once, and sizing executors to avoid contention and OOM errors.
13 Jul 2026, 11:14 UTC

Problem: Sequential Maven modules delay feedback and hide resource conflicts
When a Jenkins job builds several Maven modules one after another, the total pipeline time grows linearly with the number of modules. Teams see longer wait times for test results, a growing CI queue, and slower iteration cycles. Simply adding parallel stages without isolating Maven's local repository or accounting for shared dependencies often trades one problem for another: corrupted metadata, overlapping upstream builds, and executor starvation.
Thesis: Declarative parallel stages can cut build time if you isolate repositories, resolve dependencies first, and size executors to the workload
Using Jenkins Declarative Pipeline's parallel directive lets independent modules run concurrently on available agents. The wall‑clock time approaches the duration of the slowest module rather than the sum of all modules—provided each build gets its own Maven repository, shared dependencies are resolved once upfront, and the agent pool can sustain the concurrent demand without queuing or out‑of‑memory failures.
Worked example: Three modules with isolated local repositories
Assume a Maven multi‑module project with modules api, service, and web. They share a parent POM and a common core module but have no compile‑time dependencies on each other. The pipeline resolves dependencies once, then builds the three modules in parallel, each with a dedicated local repository directory.
pipeline {
agent none
environment {
// Base directory for per‑stage Maven repos; each stage appends its name
MAVEN_REPO_BASE = "${WORKSPACE}/.m2-repos"
MAVEN_OPTS = "-Xmx2g"
}
stages {
stage('Resolve Dependencies') {
agent { label 'docker' }
steps {
sh '''#!/bin/bash
set -e
mvn dependency:go-offline -Dmaven.repo.local=${MAVEN_REPO_BASE}/resolve
'''
}
}
stage('Build Modules') {
parallel {
stage('API') {
agent { label 'docker' }
steps {
sh '''#!/bin/bash
set -e
mvn -pl api -o clean install \
-Dmaven.repo.local=${MAVEN_REPO_BASE}/api
'''
}
}
stage('Service') {
agent { label 'docker' }
steps {
sh '''#!/bin/bash
set -e
mvn -pl service -o clean install \
-Dmaven.repo.local=${MAVEN_REPO_BASE}/service
'''
}
}
stage('Web') {
agent { label 'docker' }
steps {
sh '''#!/bin/bash
set -e
mvn -pl web -o clean install \
-Dmaven.repo.local=${MAVEN_REPO_BASE}/web
'''
}
}
}
}
}
post {
always {
cleanWs()
}
}
}
Where to run: Create a new Pipeline job in Jenkins (requires Job/Create permission) and paste the script into the Pipeline section.
Permissions: The job needs read access to the source repository and the ability to launch agents labeled docker. If you manage agents, you need Computer/Configure permission to ensure enough docker agents are online. (Exact permission names vary by Jenkins version and authorization strategy.)
Key details:
dependency:go-offlinein the first stage downloads all declared dependencies and plugins into a shared repository (${MAVEN_REPO_BASE}/resolve). The-o(offline) flag in the parallel stages forces Maven to use only what's already present, eliminating concurrent writes to the same repository.- Each parallel stage points to its own repository directory via
-Dmaven.repo.local. This prevents metadata corruption from simultaneousinstalloperations. - The
-pl moduleflag builds only the named module;-amis intentionally omitted because dependencies are already resolved. MAVEN_OPTSis set in theenvironmentblock so everyshstep inherits the same heap limit, reducing OOM risk.
Expected checks: After saving, run the job. In the classic Build Executor Status view (or Blue Ocean's pipeline visualization) you should see three executors busy simultaneously, assuming three agents labeled docker are free. Compare the total duration with a sequential version; the reduction depends on module balance and agent count.
Risks: If the agent pool has fewer than three docker agents, stages will queue, eroding the benefit. Each Maven fork still consumes heap; if MAVEN_OPTS is too high for the agent's memory, simultaneous builds can cause out‑of‑memory errors.
Trade‑off: Executor load, shared resources, and plugin prerequisites
Parallelism raises concurrent executor demand. To avoid offsetting gains:
- Profile memory: Run a single
mvn clean installon a representative agent and note peak RSS. SetMAVEN_OPTS(e.g.,-Xmx2g) so thatparallelism × heapfits within the agent's available memory. - Size the agent pool: Provision at least as many labeled agents as the maximum parallel stages you intend to run. If you cannot add agents, reduce the number of parallel branches.
- Guard external resources: If stages deploy to Nexus, query a database, or use a limited license pool, serialize those steps with the
lockstep from the Lockable Resources plugin (must be installed separately). Example:steps { lock(resource: 'nexus-deploy', quantity: 1) { sh 'mvn deploy -DskipTests' } } - Blue Ocean note: Users of Blue Ocean will see parallel branches as concurrent nodes in the pipeline graph rather than in the classic executor table.
Actionable closing
- Identify independent modules in your Maven reactor (look for lack of
<dependencies>between them). Confirm they share only already‑published or resolved artifacts. - Add a
Resolve Dependenciesstage that runsmvn dependency:go-offlineinto a shared repository. - Add a
parallelblock with one stage per module, each setting-Dmaven.repo.localto a unique subdirectory and using-o(offline) mode. - Run a test build, watch the executor view (classic or Blue Ocean), and note the wall‑clock time.
- If stages queue, add more agents or reduce parallelism; if agents show OOM, lower
MAVEN_OPTSor limit concurrent stages. - Once satisfied, replace the sequential job with the parallel version and monitor queue length and build stability over a few days.
By isolating Maven repositories, resolving dependencies upfront, and matching parallelism to your agent capacity, you can turn a long, linear Maven build into a faster, feedback‑rich pipeline without introducing flaky failures.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.