Parallel Stages and the matrix Directive
Fan out across OS and version combinations with the matrix directive, and split slow test suites into parallel branches to slash wall-clock time.
Your pipeline is only as fast as its longest serial chain. Two tools let you trade idle executors for shorter builds: explicit parallel branches and the matrix directive.
parallel for independent work
When lint, unit tests, and a security scan do not depend on each other, run them at once. The stage finishes when the slowest branch does. Add failFast true so one failing branch aborts the rest instead of wasting agents.
matrix for combinations
Testing across three Node versions and two operating systems by hand means six near-identical stages. The matrix directive generates that grid for you from a set of axes. Each cell runs the same stages with different values injected as environment variables. Use excludes to skip combinations that do not make sense.
The catch
Parallelism needs executors. Six matrix cells with one executor just queue up serially. Pair heavy matrices with elastic agents (see the scaling lesson) so the fan-out actually buys you speed.
Example
pipeline {
agent none
stages {
stage('Cross-version tests') {
matrix {
axes {
axis { name 'NODE_VERSION'; values '18', '20', '22' }
axis { name 'OS'; values 'linux', 'windows' }
}
excludes {
// Node 18 on windows not supported here
exclude {
axis { name 'NODE_VERSION'; values '18' }
axis { name 'OS'; values 'windows' }
}
}
agent { label "${OS}" }
stages {
stage('Test') {
steps {
sh 'echo Testing on Node ${NODE_VERSION} / ${OS}'
sh 'npm ci && npm test'
}
}
}
}
options { failFast() }
}
}
}When to use it
- A Go project tests against Go 1.21 and 1.22 on both Linux and macOS simultaneously using the matrix directive, replacing four separate jobs.
- A Node.js pipeline splits its 800-test suite into four parallel branches to cut the test stage from 12 minutes to 3.
- A multi-architecture Docker build uses parallel stages to build arm64 and amd64 images concurrently on labeled agents.
More examples
matrix directive for cross-platform testing
Generates six parallel test combinations (2 OS Γ 3 Node versions) automatically using the matrix directive.
stage('Test Matrix') {
matrix {
axes {
axis { name 'OS'; values 'linux', 'windows' }
axis { name 'NODE_VER'; values '18', '20', '22' }
}
stages {
stage('Test') {
agent { label "${OS}" }
steps {
sh "nvm use ${NODE_VER} && npm test"
}
}
}
}
}Parallel test sharding
Splits the Jest test suite across four parallel stages with failFast so a shard failure aborts all others immediately.
stage('Test Shards') {
failFast true
parallel {
stage('Shard 1') { steps { sh 'jest --testPathPattern="shard1"' } }
stage('Shard 2') { steps { sh 'jest --testPathPattern="shard2"' } }
stage('Shard 3') { steps { sh 'jest --testPathPattern="shard3"' } }
stage('Shard 4') { steps { sh 'jest --testPathPattern="shard4"' } }
}
}matrix with exclude
Creates a 3Γ2 matrix but excludes the Java 11 + Windows combination using the excludes block.
matrix {
axes {
axis { name 'JAVA'; values '11', '17', '21' }
axis { name 'OS'; values 'linux', 'windows' }
}
excludes {
exclude {
axis { name 'JAVA'; values '11' }
axis { name 'OS'; values 'windows' }
}
}
stages {
stage('Test') { steps { sh 'mvn test' } }
}
}
Discussion