Jenkins Parallel Stages

A long pipeline runs stage after stage, and total time equals the sum of every stage. Parallel stages let independent work run at the same moment, so total time shrinks to the length of the slowest branch. Conditional stages add a second skill: skipping work that a given change does not need.

The Layman's View

Think of a restaurant kitchen preparing a meal for a table of four. One cook grills the meat, another boils the pasta, and a third chops the salad at the same time. The meal reaches the table in the time of the slowest dish, not the total of all dishes. Parallel stages give your pipeline the same speed boost.

Sequential Versus Parallel

SEQUENTIAL (total = 5 + 8 + 6 = 19 minutes)

 Unit Tests --> UI Tests --> Security Scan
   5 min        8 min         6 min


PARALLEL (total = 8 minutes)

              +--> Unit Tests (5)
 Build ------+--> UI Tests (8)       ---> Package
              +--> Security Scan (6)

Writing Parallel Stages

Place a parallel block inside a stage, and put one nested stage in each branch.

pipeline {
    agent any
    stages {
        stage('Build') {
            steps { sh 'mvn -B package -DskipTests' }
        }
        stage('Checks') {
            parallel {
                stage('Unit Tests') {
                    steps { sh 'mvn -B test' }
                }
                stage('UI Tests') {
                    steps { sh './run-ui-tests.sh' }
                }
                stage('Security Scan') {
                    steps { sh './scan.sh' }
                }
            }
        }
        stage('Package') {
            steps { echo 'Creating release package' }
        }
    }
}

Blue Ocean and the Stage View show the three branches side by side, so a reader spots the failing branch at a glance.

Fail Fast

By default, every branch runs to the end even when one branch fails early. Add failFast true to the parallel stage and Jenkins aborts the remaining branches the moment one fails. This saves agent time when a fast failure makes the other results meaningless.

stage('Checks') {
    failFast true
    parallel {
        stage('Unit Tests') { steps { sh 'mvn -B test' } }
        stage('UI Tests')   { steps { sh './run-ui-tests.sh' } }
    }
}

Separate Agents for Each Branch

Each parallel branch can claim its own agent. Heavy branches then run on different machines instead of competing for one CPU.

parallel {
    stage('Linux Tests') {
        agent { label 'linux' }
        steps { sh './test.sh' }
    }
    stage('Windows Tests') {
        agent { label 'windows' }
        steps { bat 'test.bat' }
    }
}

Conditional Stages With when

The when directive decides whether a stage runs. A skipped stage appears greyed out in the stage view and does not count as a failure.

Common Conditions

ConditionMeaningExample
branchRuns on a matching branchwhen { branch 'main' }
environmentCompares an environment variablewhen { environment name: 'DEPLOY', value: 'yes' }
expressionEvaluates Groovy codewhen { expression { params.RUN_UI } }
changesetRuns when matching files changedwhen { changeset 'docs/**' }
not, allOf, anyOfCombine conditionswhen { not { branch 'dev' } }
stage('Deploy') {
    when {
        allOf {
            branch 'main'
            environment name: 'DEPLOY', value: 'yes'
        }
    }
    steps { sh './deploy.sh' }
}

Matrix Builds

The matrix directive runs the same stages across every combination of values. A project that supports two Java versions on two operating systems needs four test runs. A matrix defines them once.

stage('Cross Test') {
    matrix {
        axes {
            axis { name 'JAVA'; values '11', '17' }
            axis { name 'OS';   values 'linux', 'windows' }
        }
        stages {
            stage('Test') {
                steps { echo "Testing Java ${JAVA} on ${OS}" }
            }
        }
    }
}

Rules to Remember

  • Run only independent work in parallel. A test that needs another branch's output belongs in sequence.
  • Avoid branches that write to the same file or database table.
  • Count your agents. Ten branches on two executors still queue.
  • Keep branch names short so the stage view stays readable.

Measuring the Gain

Compare the pipeline duration before and after the change on the job page. A pipeline that drops from 19 minutes to 8 minutes saves 11 minutes on every commit. Across fifty commits a day, that equals more than nine hours of waiting removed from the team's day.

A Practical Starting Plan

Start small. Pick the two slowest independent stages in your pipeline and place them inside one parallel block. Run the pipeline five times and compare the average duration with your old numbers. Add a third branch only when the first change proves stable. Watch the agent queue during these runs. A parallel block that floods the queue can slow other teams, so agree on a sensible branch count with your administrator. Record the results in a short note, and share the saved minutes with your team to show the value of the change.