When Directive in Jenkins

When Directive in Jenkins

A complete, plain-English guide to running Jenkins pipeline stages only when the right conditions are true: every built-in condition, how Jenkins decides, and the traps that skip the wrong stage at the wrong time.

Picture a factory that makes toy cars. Every car goes through cutting, painting, and packing. But only the cars ordered by a shop with a special gift box also go through a “gift wrap” station. Nobody wants the gift wrap machine running on every car, and nobody wants a worker to remember by hand which cars need it. So the factory writes a simple rule on the station: “Run only when the order says gift box.” That rule is what the when directive does for a Jenkins pipeline.

Without such rules, pipelines turn into a wall of identical steps that run on every change, on every branch, at every hour. Tests take too long, deployments fire from the wrong branch, and cloud bills rise. With the when directive, one Jenkinsfile can behave like many: run quick checks on feature branches, run full tests on the main branch, and deploy only on a release tag. This guide teaches the whole topic step by step, assuming you know nothing about Jenkins yet.

1What Is the When Directive?

We begin with the simplest possible picture: what the directive is, where it sits, and what it does to a stage.

Jenkins is a tool that automates building, testing, and delivering software. You describe the work in a file called a Jenkinsfile. That file contains a pipeline, which is an ordered list of stages such as Build, Test, and Deploy. Each stage holds steps, the individual actions like running a command.

By default, a stage runs every time the pipeline reaches it. The when directive changes that. You place it inside a stage, and you describe one or more conditions. Before running the stage, Jenkins checks the conditions. If they are true, the stage runs. If they are not true, Jenkins skips the stage and moves on. In one sentence: the when directive is a gate placed at the door of a stage.

Everyday analogy

Think of a cinema. The ticket checker at the door of Screen 3 does not stop the whole building from working. The checker only decides who goes into Screen 3. Everyone else walks on to other screens. A when block is the ticket checker at one stage’s door. Other stages are untouched.

What you gain

Benefit

One file, many behaviours

You keep a single Jenkinsfile for every branch and situation instead of maintaining copies.

Benefit

Faster feedback

Slow stages run only when they matter, so developers on small changes get answers sooner.

Benefit

Lower cost

Fewer unnecessary runs means fewer machine hours, fewer container starts, and a smaller bill.

Benefit

Safer releases

Deployment stages can be limited to trusted branches or tags, so a stray feature branch cannot ship.

i
Note

The when directive belongs to Declarative Pipeline syntax, the tidy style that starts with the word pipeline. It works at the level of a whole stage. It cannot skip a single step inside a stage. For that, you use a script section, which we compare in Chapter 12.

2Why Conditional Stages Exist

To see why the directive matters, imagine a pipeline without it and follow what goes wrong.

The world before conditions

In the early days of Jenkins, a job was a long list of shell commands that ran top to bottom. If you wanted the same code to behave differently on different branches, you created separate jobs, one per branch, each with slightly different settings. Ten branches meant ten jobs. A change to the build process meant editing ten places, and someone always forgot one.

Jenkins Pipeline, which became a built-in part of Jenkins with version 2.0 in 2016, moved the job description into a text file stored next to the code. The Declarative syntax arrived shortly after and reached its first stable release in early 2017. It came with the when directive from the start, because teams practising continuous delivery immediately needed a clean way to say “only deploy from the main branch”.

10 jobs
one per branch in the old style, versus one Jenkinsfile now
2017
Declarative Pipeline reaches its first stable release
1 gate
is enough to keep a deploy stage off feature branches

The problems it solves

  • Wasted time. A documentation typo does not need a two-hour integration test suite.
  • Wasted money. Stages that start large cloud agents or containers cost real money every time they start.
  • Unsafe actions. A deployment that should only leave the main branch might run from an experiment.
  • Copy and paste drift. Separate Jenkinsfiles for separate cases slowly disagree with each other.
  • Noise. A page full of unrelated stage results hides the one that actually failed.
Everyday analogy

A fire drill is only needed when the fire alarm rings, not every ten minutes. A smart building has one rulebook: “If smoke is detected, open the emergency doors.” The building does not need a different rulebook for every hour of the day. The when directive lets a Jenkinsfile carry one rulebook for every situation.

One pipeline, many situations, no copies.

3Jenkins Basics You Need First

A handful of Jenkins words appear in every condition. Learn them once here.

Word 1

Controller and agent

The controller is the main Jenkins server that plans the work. An agent is a worker machine that does it. The controller is where conditions are usually decided.

Word 2

Multibranch pipeline

A Jenkins job type that scans a Git repository and creates a pipeline for every branch, tag, and pull request it finds.

Word 3

Branch

A line of development in Git. The main branch usually holds released code, and feature branches hold work in progress.

Word 4

Pull request

A request to merge one branch into another, reviewed by teammates. Jenkins can build it to check the change before it merges.

Word 5

Tag

A permanent label on one commit, often used for releases, such as a version number.

Word 6

Commit and changeset

A commit is one saved change in Git. The changeset is the list of files changed since the last build.

Environment variables again

Many conditions read environment variables, which are named values that Jenkins keeps about the run. For example, when Jenkins builds a branch in a multibranch job, it stores the branch name in a variable called BRANCH_NAME. Several conditions read this value behind the scenes. Because these variables exist only in certain job types, the same condition can behave differently in different kinds of job. Keep this in mind, because it explains the most common surprise in the whole topic.

!
Watch out

Some conditions, such as the branch and pull request ones, only make sense in a multibranch pipeline. In an ordinary single-branch pipeline job the information they depend on is not filled in, so they will not match the way you expect.

4Anatomy of the When Directive

Now we look at the shape of the block: where it goes, what it must contain, and how Jenkins reads it.

The shape

The word when is followed by curly braces. Inside the braces you list one or more conditions. Each condition is a small named test, such as branch followed by the branch name you care about. That is the whole structure.

The rules

1

It lives inside a stage

You cannot put it at the top of the pipeline. It gates a stage, and each stage may have its own.

2

It must contain at least one condition

An empty block is an error. Jenkins checks the file before running and reports the mistake.

3

Several conditions mean “all of them”

If you list more than one condition directly, Jenkins treats them as if they were wrapped in an “all of” group. Every one must be true for the stage to run.

4

True means run, false means skip

A skipped stage is not a failure. The build stays healthy and moves to the next stage.

5

Skipped stages are shown, not hidden

The build screen shows the stage greyed out, and the log records that the stage was skipped because of its when condition.

Everyday analogy

A club has a door rule: “Members only, and over 18.” Both parts must be true to enter. If you list two conditions in one when block, it is that kind of rule. Both are needed. If you want “members or guests with an invitation,” you must say “any of” explicitly, which we cover in Chapter 9.

What a skipped stage means for the rest

When a stage is skipped, everything inside it is skipped too: its steps, its own environment values, and its stage-level post actions. Later stages continue normally. This matters when a later stage depends on something the skipped stage was supposed to produce. If a Deploy stage expects a file made by a skipped Package stage, Deploy will fail for a reason that has nothing to do with Deploy. Keep related stages under matching conditions.

i
Tip

Before adding a condition to a stage, ask: “What later stage needs the output of this one?” Then give that later stage the same condition, or make it safe to run without the output.

5The Built-in Conditions at a Glance

Jenkins ships with a set of ready-made conditions. Here is the whole menu, each explained in a sentence, before we study the important ones in depth.

ConditionRuns the stage whenWorks in which job type
branchThe branch name matches a patternMultibranch
buildingTagThe build was started for a Git tagMultibranch
tagThe tag name matches a patternMultibranch
changeRequestThe build is for a pull request, optionally filtered by detailsMultibranch
changelogThe commit message matches a text patternAny job with source control changes
changesetThe changed files match a patternAny job with source control changes
environmentA named environment variable equals a valueAny
equalsTwo values you supply are equalAny
expressionA small Groovy expression gives trueAny
triggeredByThe build was started by a chosen cause, such as a timer or a personAny
notThe nested condition is falseAny
allOfEvery nested condition is trueAny
anyOfAt least one nested condition is trueAny

Notice the three groups. The first group asks about where the code came from: branch, tag, pull request. The second group asks about what changed: commit message and changed files. The third group asks about the state of the run: variables, expressions, and what started the build. The last three conditions are logic tools that combine the others.

Everyday analogy

Think of a doorman with a clipboard of questions. Where did you come from? What are you carrying? What time is it, and who invited you? Each built-in condition is one question on that clipboard. The doorman can ask one, several, or combine them with “and”, “or”, and “not”.

i
Note

Jenkins and its plugins evolve. Your installed version may include extra options on some conditions, or differ slightly in details. The Pipeline Syntax help page on your own Jenkins server always shows the exact forms your installation supports.

6Branch, Tag, and Pull Request Conditions

These are the most used conditions. They answer the question: “Where did this build come from?”

The branch condition

The branch condition compares the current branch name to a pattern you give it. If you give the plain word main, only the main branch matches. You can also use a glob pattern, which is a simple wildcard style. A pattern such as release-* matches release-1, release-2.0, and so on. By default, patterns are read as globs. You can also switch the comparison style to an exact match or to a regular expression when you need more precision.

Everyday analogy

A post office sorts letters by postcode. A rule like “all postcodes starting with 560 go to the south van” is a wildcard rule. It saves you from listing every single postcode. A branch pattern with a star does the same job for branch names.

The biggest surprise: only in multibranch jobs

The branch condition depends on the branch name that Jenkins records for the run. That name is only recorded for multibranch pipelines. In a plain pipeline job, the value is not there, so the condition does not match, and your Deploy stage will be skipped even on the branch you meant. If your when conditions seem to be ignored, check the job type first. This is the number one reason people believe the when directive is broken.

!
Watch out

Pull request builds in a multibranch job usually carry a branch name such as PR-42, not the name of the branch the author worked on. So a condition that says branch main will not match a pull request build, even if the pull request targets main. This is often what you want, and sometimes a shock.

The pull request condition

To detect a pull request explicitly, use changeRequest. Used alone, it is true when the build is for a pull request. You can add filters so it is true only for certain pull requests, such as those aimed at a particular target branch, or those from a certain author, or with a matching title. This lets you run extra checks on pull requests that target the release branch, while leaving other pull requests on a quicker path.

Pattern: quick checks for pull requests, full checks for main

A team gives the unit test stage no condition, so it always runs. They give the slow end-to-end test stage a condition for the main branch only. Pull requests get feedback in minutes, and main gets the full suite before any release.

The tag conditions

Release processes often start with a Git tag. The buildingTag condition is true when the build was started for a tag. The tag condition goes further and compares the tag name to a pattern, so a pattern like v* matches every version tag. Together they let you build a stage that publishes a release only when someone creates a proper release tag.

SituationCondition that fits
Run only on the main branchbranch with the name main
Run on every release branchbranch with a glob such as release-*
Run only on pull requestschangeRequest
Run on pull requests aimed at one branchchangeRequest with a target filter
Run only for any tagbuildingTag
Run only for version-style tagstag with a pattern like v*

7Changed Files and Commit Messages

Sometimes the question is not “where” but “what”. These conditions look at what actually changed.

The changeset condition

The changeset condition is true when at least one changed file matches a pattern. This is a favourite in monorepos, which are single repositories holding many services. If only the billing service folder changed, there is no reason to rebuild and retest the shipping service. A stage for the shipping service can carry a changeset condition for its own folder, and Jenkins will skip it whenever nothing in that folder moved.

Everyday analogy

A building inspector who is told only the kitchen was renovated does not re-inspect the bedrooms. They check the kitchen and go home. A changeset condition tells Jenkins which “rooms” changed so it inspects only those.

Points to know about changesets

  • It looks at the changes Jenkins recorded for this build, which are the changes since the previous build. It is not a comparison of the entire repository.
  • The very first build of a branch may have no recorded changes, so a stage guarded only by changeset can be skipped on the first run. Plan for that.
  • Patterns are globs by default, and there are options to control case sensitivity and to choose other comparison styles.
  • A shared file changes everything. If several services depend on a common library folder, include that folder in each service’s condition.
  • Pull request and branch builds can differ in what they record as changed, so test your condition on both.

The changelog condition

The changelog condition looks at the commit messages in the change list. It matches a text pattern, so a team can agree that a message containing “[skip deploy]” means “do not deploy this one”. It is simple and it works, but it relies on human discipline, and someone must remember to type the magic words. Use it for convenience switches, not for anything that protects production.

i
Tip

Prefer changeset over changelog whenever you can. Files that changed are facts. Words in a commit message are only habits.

Strengths of changeset gates

  • Saves large amounts of build time in monorepos.
  • Reads real facts about the change.
  • Needs no special commit message habits.

Weaknesses of changeset gates

  • Can be skipped on a first build with no recorded changes.
  • Misses shared code that lives in another folder.
  • Can hide a broken build until the next change touches that folder.

8Environment, Equals, Expression, and Parameters

When none of the ready-made source conditions fit, these flexible conditions let you test almost anything.

The environment condition

The environment condition checks whether a named environment variable equals a value. You give the variable name and the expected value. It is neat when a setting such as the deployment target is stored in a variable, and you want a stage to run only for one target.

The equals condition

The equals condition compares two values that you provide, an expected one and an actual one. It is the tidy way to test a build parameter. For example, a yes-or-no parameter asking “should we deploy?” can be compared to the value you expect.

The expression condition

The expression condition is the most powerful and the most dangerous. You write a small Groovy expression, and the stage runs when it gives true. You can test anything: a parameter, a variable, a calculation. Because it is free-form, it is also the easiest place to make a mistake.

Everyday analogy

The ready-made conditions are like a set of labelled light switches in a house. The expression condition is like handing a stranger a screwdriver and the fuse box. It can do anything the switches can, and much more, but a small slip can leave you in the dark.

The text-versus-truth trap

Environment variables are always text. Even if you set a variable to the word false, Jenkins stores the text “false”. In Groovy, any non-empty text counts as true when tested for truthiness. So an expression that simply asks whether the variable is set will say yes, and the stage will run even though the value says false. The safe habit is to compare the text to the exact word you expect, and never to test bare text for truth.

Build parameters behave differently. A parameter defined as a true-or-false type is a real boolean when read through the parameters object, and it can be tested directly. But the same parameter read through the environment becomes text again. Decide which way you read it, and stay consistent.

How the value is readIts typeSafe way to test it
Environment variableTextCompare to the exact word, such as “true”
Boolean build parameter, read as a parameterTrue or falseTest it directly, or compare with equals
Boolean build parameter, read as an environment variableTextCompare to the exact word
Choice parameterTextCompare to the chosen option
!
Watch out

A variable defined in the same stage’s own environment block may not be visible yet when that stage’s when is evaluated. To be safe, define values that conditions depend on at pipeline level, and test the result on your own Jenkins version.

9Combining Conditions: Not, All Of, Any Of

Real rules are rarely one question. This chapter shows how to combine tests, like Lego bricks, into exactly the rule you need.

Logic

not

Flips a condition. “Not the main branch” runs the stage on every branch except main.

Logic

allOf

True only if every nested condition is true. This is what you get by default when you list several conditions.

Logic

anyOf

True if at least one nested condition is true. “Main branch, or any release branch.”

Logic

Nesting

You can place these inside each other to build rules such as “on main, or on a tag, but only if the deploy flag is on”.

flowchart TD
  A["Stage reached"] --> B{"Is the build for the main branch"}
  B -->|Yes| D{"Is the deploy flag on"}
  B -->|No| C{"Is the build for a version tag"}
  C -->|Yes| D
  C -->|No| S["Skip the stage"]
  D -->|Yes| R["Run the stage"]
  D -->|No| S
    
Figure 1. A rule built from any-of and all-of: on main or on a version tag, and only if the deploy flag is on.

The picture shows the thinking. First ask where the build came from: the main branch, or a version tag. If either is true, move on to the flag. If the flag is also on, run. Any other path ends in a skip. In the Jenkinsfile, this is an allOf group that contains one anyOf group and one flag check.

A caution on evaluation order

Jenkins generally works through nested conditions in order and may stop early once the answer is known, just as you stop reading a list of requirements once one fails. Do not build conditions that depend on a side effect of an earlier one, and keep every condition free of surprises such as running commands or changing values. A condition should only ask a question. It should never do work.

Everyday analogy

A theme park ride sign says: “You must be 120 cm tall, and either have a wristband or a paper ticket.” The staff check height first. If you are too short, they do not bother checking your ticket. Nested conditions work in the same spirit.

i
Tip

If a rule needs more than three or four nested layers, that is a sign to simplify. Compute one clear yes-or-no early in the pipeline, store it, and let the stage test that single value.

10Build Causes with triggeredBy

A build can start for many reasons. The triggeredBy condition lets a stage react to why the build began.

Every Jenkins build records a cause: the reason it started. Common causes include a person pressing the build button, a timer firing on a schedule, a change detected in source control, or another job finishing upstream. The triggeredBy condition is true when the build’s cause matches the one you name. You may also give extra detail, such as a specific user.

CauseMeaningTypical stage that uses it
A timerA scheduled run, often overnightLong, expensive test suites
A personSomeone pressed the build buttonManual maintenance or cleanup stages
Source control changeJenkins noticed a new commitNormal build and quick tests
Upstream jobAnother Jenkins job finished and started this oneFollow-on packaging or publishing
Everyday analogy

A restaurant kitchen treats an online order, a phone order, and a walk-in order the same at the stove but differently at the counter. Where the order came from decides who packs it and how. The build cause tells a stage where its order came from.

Pattern: the nightly deep check

A team keeps day-time builds quick by giving a two-hour performance test a triggeredBy timer condition. It runs on the overnight schedule, and developers still get their results in minutes during the day.

Pattern: manual cleanup

A rarely needed cleanup stage carries a condition for a person starting the build. It never runs by accident from a commit, only when someone deliberately asks for it.

i
Note

The cause names you can use depend on the plugins installed on your Jenkins. Check the Pipeline Syntax help page on your server to see the exact cause names available to you.

11How It Works Internally and When It Is Evaluated

This chapter lifts the lid on the directive. Knowing the order of events explains why an agent sometimes starts for a stage that then gets skipped.

The moment of decision

When Jenkins starts a run, the controller reads the Jenkinsfile and turns the Declarative syntax into an internal plan. As the run reaches each stage, the controller checks whether the stage has a when block. If it does, the controller works out the conditions using the information it holds about the run: the branch name, the change list, the environment variables, the parameters, and the build cause. The answer is yes or no. Yes means the stage runs. No means Jenkins marks it skipped and moves to the next one.

Most conditions are simple lookups against data the controller already holds, so they are fast. An expression condition runs a small piece of Groovy on the controller, and Jenkins normally runs that in a protected mode called the sandbox, which limits what it may call. This protection matters, and it is why some clever code you would happily run on your laptop is rejected in a pipeline until an administrator approves it.

The surprise: the agent may already be running

By default, if a stage names its own agent, Jenkins first gets that agent ready and only then evaluates the when block. That means a stage can start a machine, start a container, or allocate a cloud worker, and then discover that its condition is false and skip everything. For cheap agents this is unimportant. For expensive ones, such as large cloud machines or Kubernetes pods, it is real waste.

The fix is a small option inside the when block called beforeAgent. When you set it to true, Jenkins evaluates the conditions first and only starts the agent if the answer is yes.

sequenceDiagram
  participant Ctl as Jenkins Controller
  participant Cond as When Conditions
  participant Agt as Agent for the Stage
  Note over Ctl,Agt: Default behaviour
  Ctl->>Agt: Request the stage agent
  Agt-->>Ctl: Agent is ready
  Ctl->>Cond: Evaluate the conditions
  Cond-->>Ctl: False so skip the stage
  Note over Ctl,Agt: With beforeAgent set to true
  Ctl->>Cond: Evaluate the conditions first
  Cond-->>Ctl: False so skip the stage
  Ctl->>Ctl: Move on with no agent started
    
Figure 2. Default order versus the beforeAgent option.
Everyday analogy

Imagine calling a taxi before checking whether the party is still on. If the party is cancelled, you paid the taxi for nothing. Checking first, then calling the taxi, is what beforeAgent gives you.

Three timing options

OptionEffectWhy use it
beforeAgentEvaluate conditions before the stage’s agent startsAvoid paying for agents that will not be used
beforeInputEvaluate conditions before the stage waits for human approvalDo not ask a person to approve a stage that will be skipped
beforeOptionsEvaluate conditions before the stage’s options are appliedAvoid taking locks or starting timers for a skipped stage

When more than one is set, Jenkins follows a fixed priority, with the options step first, the input step second, and the agent step third. Availability of some of these options depends on the Declarative Pipeline plugin version, so confirm what your server supports.

i
Tip

Make beforeAgent your habit for any stage that has its own agent, especially container or cloud agents. It costs nothing and often saves real money.

Nested and parallel stages

Stages can be nested inside other stages, and stages can run side by side in parallel groups. Each stage can carry its own when. If the outer stage is skipped, everything inside it is skipped without further questions. If the outer stage runs, each inner stage checks its own condition in turn. Matrix-style stages, which run the same work over combinations of values, can also carry a when. Check your Jenkins version for the exact places it is honoured.

Saved state

Jenkins saves the progress of a pipeline so it can resume after a restart. Conditions are evaluated as each stage is reached, using the data recorded for the run, so a restart in the middle of a run does not change the meaning of the conditions that have already been decided.

12When Versus Other Ways of Deciding

The when directive is not the only way to make a pipeline choose. Picking the right tool keeps your file clear.

ToolScope of decisionStyleBest for
The when directiveA whole stageDeclarative, readableDeciding if a stage runs at all
An if inside a script sectionOne or more stepsGroovy codeSkipping individual steps, or complex logic
Post conditions such as always, success, failureActions after a stage or the run endsDeclarativeReacting to the result of the run
Scripted Pipeline if statementsAnythingFull GroovyAdvanced flows where Declarative is too rigid
Build parametersThe values people chooseInput formHuman choices that feed a condition

An important distinction is between before and after. The when directive decides before a stage whether it should run. The post conditions decide after the work is done what to do next depending on the result. Both use similar-looking words, but they answer different questions.

Everyday analogy

A fridge magnet that says “Only water the plants if the soil is dry” is a rule checked before watering. A note that says “If the plant wilts, call the gardener” is a rule checked after. The first is when. The second is a post condition.

Choose when for

  • Gating whole stages such as Deploy or Integration Test.
  • Rules that a colleague should be able to read at a glance.
  • Clear skipped-stage display on the build screen.

Avoid when for

  • Skipping one step within a stage. Use a script section.
  • Long, tangled logic. Simplify or move it into a shared script.
  • Anything that should depend on the outcome of the stage itself.

13Security Considerations

Conditions are often used to guard deployments. That makes it important to know what they can and cannot protect.

A condition is a rule, not a lock

A when block that says “deploy only from the main branch” is a rule written in the Jenkinsfile. Anyone who can change the Jenkinsfile can change the rule. On a pull request from a contributor, the Jenkinsfile in that pull request may be the one that gets used, depending on how your job is configured. A malicious change could remove the condition and add a step that steals secrets. Therefore a when block must never be your only line of defence.

Defence 1

Trusted Jenkinsfile source

Configure multibranch jobs so that changes to the pipeline file from untrusted contributors are not used for builds that can reach secrets.

Defence 2

Scoped credentials

Store deployment credentials where only trusted jobs or branches can use them, so a skipped rule cannot expose them.

Defence 3

Branch protection

Use your Git host to require reviews before code reaches the branches that trigger deployment.

Defence 4

Approval gates

For production, add a human approval step so a single condition is never the only thing between code and users.

Expression conditions and the sandbox

The expression condition runs Groovy on the controller. Jenkins guards this with the sandbox and a script approval process. When a Jenkinsfile in a repository uses something the sandbox blocks, an administrator sees an approval request. Approve these only after reading exactly what the code does. Blindly approving a method can open a path for someone to run harmful code on your controller.

Do not let user input drive a condition unchecked

If a build parameter is free text and you feed it into a condition, someone could type a value that triggers a stage you did not intend. Prefer parameters with fixed choices, and compare them to known values.

!
Watch out

A skipped stage is silent. If a security scan is guarded by a when block and the condition is accidentally never true, the scan simply never runs, and everything looks green. Review conditions on security stages as carefully as the scans themselves.

A condition that decides is not a lock that protects.

14Monitoring, Logging, and Troubleshooting

When a stage runs that should not, or does not run that should, here is how to find out why without guessing.

What Jenkins shows you

  • The stage view. Skipped stages are drawn in a faded style, so you can see at a glance which ones did not run.
  • The console log. Jenkins writes a message that a stage was skipped due to its when conditional. This is your first clue.
  • The Pipeline Syntax page. It lists the exact condition forms available on your server.
  • Replay. Lets you edit and rerun the pipeline to test a changed condition without committing.
flowchart TD
  A["A stage ran or skipped unexpectedly"] --> B{"Is the job a multibranch pipeline"}
  B -->|No| C["Branch and pull request conditions cannot match so use another test"]
  B -->|Yes| D{"Did you print the values the condition reads"}
  D -->|No| E["Print the branch name and variables in an earlier stage"]
  D -->|Yes| F{"Is the value text compared as truth"}
  F -->|Yes| G["Compare to the exact word instead"]
  F -->|No| H{"Is it a first build or a pull request"}
  H -->|Yes| I["Check the changeset and the PR branch name"]
  H -->|No| J["Review nesting and the logic between allOf and anyOf"]
    
Figure 3. A simple decision path for conditions that do not behave.

Common symptoms and causes

SymptomLikely causeWhat to do
Deploy stage never runs on mainThe job is not multibranch, so the branch name is not recordedUse a multibranch job, or test something else
Stage skipped on a pull request into mainThe build’s branch name is the pull request label, not mainUse changeRequest with a target filter
Stage runs even though a flag says falseThe flag is text, and any non-empty text is treated as trueCompare to the exact word
Changeset stage skipped on the first buildNo changes were recorded yetAdd another condition for a first build, or a manual override
Agent started for a skipped stageConditions are evaluated after the agent by defaultSet beforeAgent to true
Later stage fails after a skipIt needed output from the skipped stageGive it a matching condition
Approval prompt for a skipped stageConditions are evaluated after the input by defaultSet beforeInput to true

A helpful debugging habit

Add a small stage near the top, with no condition, that prints the branch name, the change identifier, the build cause, and the parameters. Run the pipeline once and read the values. Most puzzles solve themselves once you see the real values that the conditions receive. Remove this stage when you are done, and never print secrets in it.

Signals worth tracking over time

Count how often each guarded stage is skipped. A stage that is skipped one hundred percent of the time may have a condition that can never be true. A stage that never skips may have a condition that is too loose. Both are worth a look during regular pipeline reviews.

15Design Patterns and Anti-patterns

Patterns are habits that keep pipelines calm. Anti-patterns are habits that keep creating puzzles at two in the morning.

Patterns that help

Pattern

Fast lane, slow lane

Quick checks run always. Slow or expensive checks are gated to main, to nightly builds, or to release tags.

Pattern

Named decision variable

Work out one clear yes-or-no early, such as “should deploy”, and let stages test that single value instead of repeating long rules.

Pattern

Guarded agents

Use beforeAgent on every stage with a costly agent so nothing starts for a skipped stage.

Pattern

Monorepo per-folder gates

Give each service its own stage with a changeset for its folder plus shared code folders.

Pattern

Tag-based releases

Publish only when a tag matching a version pattern is built, so releases are deliberate and traceable.

Pattern

Manual escape hatch

Give important stages a boolean parameter to force them on, so a person can override a condition when needed.

Anti-patterns to avoid

ANTI-PATTERN 01 Avoid
Context

A team guards a stage with a bare Groovy expression that asks whether a text variable is set.

What goes wrong

The variable holds the word false. Any non-empty text counts as true, so the stage runs anyway. A test suite is skipped, or a deployment happens when it should not.

Better decision

Compare the text to the exact word expected, or read a typed boolean parameter as a parameter.

ANTI-PATTERN 02 Avoid
Context

Every stage carries a slightly different, hand-written condition, copied and adjusted over time.

What goes wrong

Nobody can explain the full behaviour of the pipeline. A change to the branching strategy means editing a dozen blocks, and one is always missed.

Better decision

Define one or two named decision values near the top, and have stages test those. When the rule changes, there is one place to edit.

ANTI-PATTERN 03 Avoid
Context

A security scan stage is guarded by a condition that only runs it on the main branch.

What goes wrong

Vulnerabilities enter through feature branches and are only found after merging, when they are costlier to fix. And if the condition breaks, the scan quietly never runs.

Better decision

Run cheap scans on every change. Gate only the heaviest ones, and alert when a critical stage has not run for a set period.

16Worked Scenario: One Pipeline, Five Situations

Let us put everything together. We follow a single imaginary Jenkinsfile through five different events and see which stages run each time.

The imaginary pipeline

A small team runs an online shop. Their multibranch Jenkinsfile has six stages. Compile and Unit Tests have no condition, so they always run. Integration Tests carry a condition for the main branch, and also run when the build was started by the overnight timer. Security Deep Scan runs only for the overnight timer. Publish Package runs only when a version-style tag is built. Deploy to Staging runs on the main branch only, and has beforeAgent set so no cloud machine starts for other builds.

StageFeature branch pushPull request into mainMerge to mainVersion tagOvernight timer
CompileRunsRunsRunsRunsRuns
Unit TestsRunsRunsRunsRunsRuns
Integration TestsSkippedSkippedRunsSkippedRuns
Security Deep ScanSkippedSkippedSkippedSkippedRuns
Publish PackageSkippedSkippedSkippedRunsSkipped
Deploy to StagingSkippedSkippedRunsSkippedSkipped

Reading the table like a story

1

A developer pushes to a feature branch

Only compile and unit tests run. The developer has a result in a few minutes and the shared machines stay free.

2

The developer opens a pull request into main

The build name is a pull request label, so the main branch condition does not match. Reviewers see the same quick checks.

3

The pull request is merged

Now the build is for the main branch. Integration tests run, then the staging deployment starts on its own cloud agent.

4

Someone creates a version tag

The tag build compiles, tests, and publishes the package. Nothing is deployed, because deployment is tied to the main branch.

5

The overnight timer fires

The heaviest checks run while everyone sleeps: integration tests and the deep security scan.

Everyday analogy

A hospital has many departments, but a patient with a sore throat does not visit all of them. Reception looks at the reason for the visit and sends the patient only to the departments that matter. The Jenkinsfile is the hospital, each stage is a department, and each when block is the receptionist’s rule for that department.

i
Tip

Draw a table like the one above for your own pipeline before you write any conditions. If a cell surprises you, fix the design first, then write the code.

Spotting a hidden problem

Notice that the version tag build skips Integration Tests. That means a tag could be published from a commit whose integration tests have never been run in that exact build. In this design the team relies on the fact that tags are created only from commits already tested on main. That is a reasonable choice, but it is a decision the team should make consciously, and write down. Tables like this one are excellent for uncovering such hidden assumptions.

17Performance, Scalability, and Cost

The directive is small, but its effect on speed and cost can be large. This chapter explains why.

The cost of a build you did not need

Every stage that runs uses some resource: processor time, memory, network, and often money. A large organisation may run thousands of builds per day. If each build runs ten minutes of unnecessary work, that adds up to hundreds of hours of wasted machine time every day. Gating expensive stages so they run only when they matter is one of the cheapest ways to reduce that waste.

1,000
builds a day, as an example of a busy team
10 min
of needless work per build in the example
~167 hrs
of machine time wasted per day in that example

The numbers above are only an illustration to show the scale, since one thousand builds times ten minutes is ten thousand minutes, or about one hundred sixty-seven hours. Your own numbers will differ, but the shape of the problem is the same.

Where the savings come from

Saving

Fewer stage runs

A skipped stage uses almost no resources, so a well-placed condition removes its cost entirely.

Saving

Fewer agent starts

With beforeAgent, a skipped stage never starts its container, virtual machine, or cloud worker.

Saving

Shorter queues

Jenkins has a limited number of executors. When fewer stages compete for them, other builds wait less.

Saving

Faster feedback

A developer who gets an answer in five minutes instead of fifty can fix a problem while it is still fresh in mind.

Scaling across many repositories

As an organisation grows from a handful of pipelines to hundreds, the rules for who runs what start to matter more than any single stage. Teams with many repositories often place their standard conditions inside a shared library, which is a central bundle of pipeline code that every project can use. Then a change such as “run the deep scan only at night” is made once and reaches every project. Without such sharing, each repository slowly develops its own slightly different rules.

Cost of the conditions themselves

Most conditions are nearly free because they read data Jenkins already has. The exception is a condition that does real work, for example an expression that calls a slow service or reads a large file. Since conditions are evaluated on the controller, a slow one delays the decision and can put extra load on the busiest machine in your system. Keep conditions quick and simple. If a decision needs real work, do that work in an earlier stage, store the answer, and let the condition read the stored answer.

Everyday analogy

A supermarket cashier asks one quick question: “Do you have a loyalty card?” A cashier who phoned head office to check every customer’s history would make the whole line wait. Keep your conditions like the quick question, not like the phone call.

!
Watch out

Saving time by skipping a stage is only a win if the stage was truly unnecessary. If a skipped check would have caught a real defect, the savings are paid back later with interest. Always weigh speed against the protection the stage gives.

Skip the work that does not matter. Never skip the work that protects.

18Advantages, Trade-offs, Best Practices, and Common Mistakes

A balanced view of the directive, and the habits that keep it working for you.

Advantages

  • Readable, declarative rules that teammates understand quickly.
  • One Jenkinsfile can serve every branch and situation.
  • Skips whole stages cleanly, with a visible record.
  • Saves time, money, and machine capacity.
  • Ready-made conditions cover most common needs.
  • Composable through not, all of, and any of.

Disadvantages and trade-offs

  • Works only at stage level, not step level.
  • Some conditions need multibranch jobs.
  • Skips are silent, so broken conditions can hide problems.
  • Values are text, so truth tests are easy to get wrong.
  • Evaluation timing defaults can start agents needlessly.
  • Complex nesting becomes hard to read.

Best practices in one place

  1. Prefer facts over habits. Use branch, tag, and changeset conditions before commit message conditions.
  2. Use multibranch jobs when your rules depend on branches, tags, or pull requests.
  3. Set beforeAgent to true on stages that have expensive agents.
  4. Compare text to exact words. Never test bare text for truth.
  5. Keep conditions free of side effects. They should only ask questions.
  6. Keep related stages under matching conditions, so no stage waits for output that was skipped.
  7. Name your decisions. A single clear value near the top beats many copies of a long rule.
  8. Add an override. A boolean parameter lets a person force a stage when needed.
  9. Watch skip rates. A stage that never runs, or always runs, deserves a review.
  10. Protect deployment separately. Use scoped credentials, branch protection, and approvals in addition to conditions.

The mistakes seen most often

Mistake 1: branch condition in a plain job

A team writes a condition for the main branch, but the job is a single-branch pipeline job. The branch name is not recorded, so the deploy stage is always skipped. The fix is to use a multibranch job.

Mistake 2: forgetting the pull request naming

A team expects pull requests into main to match a condition for main. The build’s branch name is the pull request label, so they never match. The fix is to use changeRequest with a target filter.

Mistake 3: skipping a dependency

A Package stage is gated by a changeset, but the Deploy stage that uses its output is not. When no files change, Package is skipped and Deploy fails. The fix is to match the conditions.

Mistake 4: paying for skipped agents

A Kubernetes agent starts for a stage that will be skipped, every build. The fix is to set beforeAgent to true.

19Real-World Usage Patterns

Here is how the when directive tends to appear in real delivery pipelines. These are illustrative patterns in general terms, not claims about the private setups of any particular company.

Jenkins is one of the most widely used automation servers, and large engineering organisations have publicly described running it at scale. What tends to be common is a habit of careful gating: quick checks for everyone, heavier work for trusted branches, and deliberate release steps. The patterns below show that habit in practice.

Pattern: an online shop with fast pull requests

A shop’s pipeline runs compile and unit tests on every change. Browser-based end-to-end tests are gated to the main branch and nightly builds. Developers see results in minutes, while the shop still gets a full check before each release.

Pattern: a monorepo with many services

A company keeps fifty services in one repository. Each service has a stage with a changeset condition for its own folder and shared libraries. A change to one service rebuilds only that service and anything it depends on.

Pattern: version tags trigger releases

A software vendor publishes packages only when a tag that matches its version pattern is built. Nobody can publish by accident from an ordinary branch, and every published package traces to a tag.

Pattern: nightly deep checks

A bank keeps performance and security deep-scan stages behind a timer cause. They run overnight, and the results are waiting in the morning without slowing daytime work.

Pattern: promotion with approval

A delivery team deploys to a test environment automatically on main. The production stage has a branch condition, a beforeInput option, and a human approval, so nobody is asked to approve a deployment that would have been skipped anyway.

i
Note

Jenkins is often used together with Git hosting services, Docker, Kubernetes, and cloud tools. The when directive is the piece that lets one Jenkinsfile respond sensibly to all the different events that these systems produce.

20Frequently Asked Questions

Q1Can I put a when block at the top of the whole pipeline?
No. The when directive belongs inside a stage. To keep an entire pipeline from doing anything on certain events, guard each of its stages, or control triggers and branch discovery in the job configuration.
Q2What happens when a stage is skipped?
Jenkins marks it as skipped, records a message in the log, and continues with the next stage. The build result is not affected by the skip itself.
Q3If I list two conditions, does the stage need one or both?
Both. Listing several conditions directly is treated as if they were inside an “all of” group. If you want “either”, wrap them in an “any of” group.
Q4Why does my branch condition never match?
Usually because the job is not a multibranch pipeline, so no branch name is recorded. Another common reason is that the build is for a pull request, whose name is a pull request label.
Q5How do I run a stage only on pull requests?
Use the changeRequest condition. You can add filters, such as the target branch, to narrow it further.
Q6How do I skip a stage when only documentation changed?
Wrap a changeset condition for documentation files in a “not” group. The stage will then be skipped when the only changed files are documentation. Check how your Jenkins version reports changes for the first build and for pull requests.
Q7Why did an agent start for a stage that was skipped?
By default, the conditions are evaluated after the stage’s agent has been prepared. Set beforeAgent to true inside the when block to evaluate them first.
Q8Why does a stage run even though my flag says false?
Environment values are text, and non-empty text counts as true when tested for truthiness. Compare the value to the exact word you expect.
Q9Can I skip a single step and not the whole stage?
Not with the when directive. Use an if inside a script section around that step.
Q10Can I run a stage only for builds started by a timer?
Yes, with the triggeredBy condition set to the timer cause. The exact cause names depend on installed plugins, so confirm them on your Pipeline Syntax help page.
Q11Is a when condition enough to protect production?
No. It is a rule inside a file that people can edit. Combine it with branch protection, scoped credentials, trusted Jenkinsfile sources, and human approvals.
Q12Where can I see the exact list of conditions my server supports?
Every Jenkins server has a Pipeline Syntax reference page that documents the available directives and their options. That page is the most reliable source for your installed versions.

21Summary and Key Takeaways

Key Takeaways

  • The when directive is a gate at the door of a stage. True means the stage runs, false means it is skipped, and a skip is not a failure.
  • Several conditions mean all of them. Use anyOf for “either”, not for “except”, and keep nesting shallow.
  • Know your job type. Branch, tag, and pull request conditions need a multibranch pipeline, and pull request builds carry a pull request name, not the source branch name.
  • Every environment value is text. Compare to the exact word you expect, and never test bare text for truth.
  • Set beforeAgent to true on stages with costly agents so nothing starts for a stage that will be skipped.
  • Keep dependent stages consistent. If a stage is skipped, later stages that need its output must be skipped or made safe.
  • A condition is a rule, not a lock. Protect production with scoped credentials, branch protection, trusted pipeline sources, and human approvals as well.