skip to content

In a Jenkins declarative pipeline, what does a stage's when directive do, and what does beforeAgent true change?

level: middleimportance: should knowfreq 55%

answer

  1. a stage-level guard, not a failure
  2. skipped is still green
  3. conditions compose with allOf and anyOf
  4. order matters: agent first by default
  5. one boolean saves a provisioned pod

basics

~20 s

A stage's when directive decides at runtime whether that stage executes; a false condition marks the stage skipped without failing the build. By default the condition is checked after the stage's agent is allocated, and beforeAgent true evaluates it first instead.

solid answer

~50 s

`when` is a declarative-only stage directive holding one or more conditions. If they evaluate false, Jenkins reports the stage as skipped and moves on — the build result is untouched, so a skipped deploy stage still finishes green. The built-ins include `branch`, `tag`, `buildingTag`, `changeset`, `changelog`, `changeRequest`, `environment`, `equals`, `triggeredBy` and the general-purpose `expression`, combined with `allOf`, `anyOf` and `not`. The catch is *when* the check runs: by default Jenkins enters the stage's agent first, so a stage skipped by `when` can still have provisioned a Kubernetes pod, cloned the repository and burned a minute. Setting `beforeAgent true` inside the `when` block evaluates the condition before the agent is acquired. Its siblings `beforeInput true` and `beforeOptions true` do the same for the stage's `input` prompt and its `options`, so you do not ask a human to approve a stage that was going to be skipped.

code

groovy · 18 lines
groovy
pipeline {
    agent none
    stages {
        stage('Deploy') {
            agent { label 'deployer' }
            when {
                beforeAgent true
                allOf {
                    branch 'main'
                    not { changeRequest() }
                }
            }
            steps {
                sh './deploy.sh'
            }
        }
    }
}

go deeper

for a junior

Know that when guards a single stage and that a skipped stage does not fail the build; be able to write when { branch 'main' } around a deploy stage.

for a middle

Explain the condition vocabulary and how allOf, anyOf and not compose, and state clearly that the default evaluation happens after the agent is entered.

for a senior

Demonstrate the operational instinct: put beforeAgent true on conditional stages with heavyweight agents, use beforeInput so humans are not asked to approve stages that will skip, and know what information is unavailable before the agent exists.

for a principal

Decide where conditional logic belongs at all — inside one pipeline's when directives, or split across separate pipelines — and weigh the readability cost of a Jenkinsfile whose real behaviour depends on a dozen runtime conditions.

## What when does `when` is a stage-level directive in declarative syntax — scripted has no equivalent and uses an ordinary Groovy `if`. It wraps one or more conditions that Jenkins evaluates at runtime for that stage: ```groovy stage('Deploy') { when { branch 'main' } steps { sh './deploy.sh' } } ``` When the conditions are false, the stage is **skipped**: its steps do not run, the build log records that it was skipped due to the when conditional, and the visualisation greys it out. Crucially, skipping is not failing. The build's overall result is unaffected, so a pipeline whose deploy stage is skipped on feature branches still ends SUCCESS. Candidates who expect UNSTABLE or a red build here have not used it. ## The built-in conditions The conditions worth knowing, all real directive names: - `branch 'main'` — matches the branch name, with wildcard and regex forms. Only meaningful in multibranch pipelines, where Jenkins knows the branch. - `tag` and `buildingTag()` — the build is for a tag, optionally matching a pattern. - `changeRequest()` — the build is for a change request (a pull or merge request), with optional attribute filters such as the target branch. - `changeset 'src/api/**'` — the files changed in this build match a pattern. `changelog` instead matches a regular expression against the commit messages. - `environment name: 'DEPLOY_TO', value: 'production'` — an environment variable has a specific value. `equals expected: 2, actual: currentBuild.number` compares two values generally. - `triggeredBy 'TimerTrigger'` — the build was started by a particular cause. - `expression { return params.RUN_TESTS }` — arbitrary Groovy returning a boolean; the general escape hatch. They compose with `allOf { }`, `anyOf { }` and `not { }`: ```groovy when { beforeAgent true allOf { branch 'main' not { changeRequest() } expression { params.DEPLOY == true } } } ``` ## The default evaluation point, and why it costs you This is the part interviewers push on. By default the `when` condition is evaluated **after** Jenkins has entered the stage's agent. If the stage declares `agent { kubernetes … }` or `agent { docker 'node:22' }`, that means a pod or container has already been provisioned, the workspace prepared and (usually) the repository checked out — all for a stage that is then skipped. On a pipeline with a dozen conditionally-skipped stages, each with its own agent, that is minutes of wasted capacity per build and real cloud cost. `beforeAgent true` fixes it: ```groovy stage('Deploy to prod') { agent { label 'deployer' } when { beforeAgent true branch 'main' } steps { sh './deploy.sh' } } ``` Now the condition is checked first and the agent is only acquired if the stage will actually run. The obvious constraint follows from the ordering: a condition evaluated before the agent exists cannot inspect anything on that agent — no reading a file from the workspace, no shelling out. It can only use information the controller already has: branch, tag, parameters, environment variables set at pipeline level, build causes. ## Its two siblings `beforeInput true` moves the evaluation ahead of the stage's `input` directive, so Jenkins does not prompt a human to approve a stage that the condition was going to skip. `beforeOptions true` moves it ahead of the stage's `options`, which matters when those options are expensive or have side effects. When more than one is set, the earliest applies first: options, then input, then agent. All three are booleans written inside the `when` block itself, not beside it. ## The scripted equivalent, and why it is not the same In scripted syntax you would write `if (env.BRANCH_NAME == 'main') { stage('Deploy') { … } }`. The behaviour looks similar, but the stage simply never exists rather than existing-and-skipped, so it does not appear greyed out in the visualisation and the stage list differs between builds. That is a concrete example of what the declarative schema buys: a static stage list that the UI and restart-from-stage can rely on. ## Practical guidance Prefer specific built-in conditions to `expression`: `branch 'main'` states intent and is cheap, whereas an expression is opaque Groovy that runs under the sandbox. Add `beforeAgent true` by default on any conditional stage with a heavyweight agent — there is rarely a reason not to, and forgetting it is the most common performance defect in otherwise correct Jenkinsfiles.

  • Does a stage skipped by when make the build unstable or failed?
    No. Skipping is a normal outcome: the steps do not run, the log notes the stage was skipped due to the when conditional, and the build result is untouched. A pipeline whose deploy stage is skipped on a feature branch finishes SUCCESS.
  • What can a when condition not look at once beforeAgent true is set?
    Anything that only exists on the agent. With the condition evaluated before the executor is acquired there is no workspace and no shell, so you cannot read a checked-out file or run a command. You are limited to controller-side information: branch and tag names, build parameters, causes, and pipeline-level environment variables.
  • When would you use expression instead of a built-in when condition?
    When no built-in expresses the rule — combining a parameter with a computed value, or testing something only Groovy can compute. Prefer built-ins otherwise: branch, tag and changeset state intent clearly, are cheap, and avoid running arbitrary Groovy through the sandbox on every build.

saying these in an interview costs you the question

  • Thinks a skipped stage fails or destabilises the build
  • Assumes when is checked before the agent by default
  • Believes when also works in scripted pipelines
  • Uses expression for conditions branch already covers
  • Confuses changeset (files) with changelog (commit messages)

context