← Back to Articles         
Pipeline Conditions and Conditional Execution

Pipeline Conditions and Conditional Execution

Published on 08 Oct 2026     8 min read Azure DevOps
YAML Pipelines

1. What are Conditions in Azure DevOps?

In Azure DevOps YAML Pipelines, conditions determine whether a particular stage, job, or step should execute or be skipped.

Conditions are commonly used to control pipeline execution based on:

  • Branch: Run deployment only when code is merged into main.

  • Environment: Deploy to DEV, UAT, or PROD based on the selected environment.

  • Build result: Execute a job only when the previous job succeeds.

  • Pull Request: Run validation jobs only for Pull Requests.

  • Custom variables: Execute a task when a particular condition is satisfied.

Real-time example

Suppose we have an ASP.NET Core Web API application with two Git branches:

  • dev — Development branch

  • main — Production branch

We want the following behavior:

Developer Pushes Code
        |
        v
Azure Pipeline Triggered
        |
        v
Check Branch
        |
        +---- dev
        |      |
        |      v
        |   Build Application
        |      |
        |      v
        |   Deploy to DEV
        |
        +---- main
               |
               v
            Build Application
               |
               v
            Deploy to PROD

This is achieved using YAML conditions.

2. Basic Syntax of Conditions

Azure DevOps uses the condition: property.

condition: expression

Example:

steps:
- script: echo "Build Application"
  condition: succeeded()

Here, the step executes only if its dependencies have succeeded.

Common condition functions

Function

Purpose

succeeded()

Runs when dependencies succeed

failed()

Runs when dependencies fail

always()

Runs regardless of success or failure, including cancellation where possible

succeededOrFailed()

Runs after success or failure, but not cancellation

eq(a, b)

Checks whether two values are equal

ne(a, b)

Checks whether two values are different

and(a, b)

Both conditions must be true

or(a, b)

At least one condition must be true

not(a)

Reverses a condition

Example:

condition: eq(variables['Build.SourceBranchName'], 'main')

This condition evaluates to true when the source branch name is main.

3. Conditional Execution Based on Branch

Azure DevOps provides predefined variables that identify the source branch.

Two important variables are:

Variable

Example value

Build.SourceBranch

refs/heads/main

Build.SourceBranchName

main

Example: Run a job only for the main branch

trigger:
- dev
- main

pool:
  vmImage: 'ubuntu-latest'

jobs:
- job: Build
  displayName: 'Build Application'
  steps:
  - script: echo "Building application"

- job: DeployProduction
  displayName: 'Deploy to Production'
  dependsOn: Build

  condition: and(
    succeeded(),
    eq(variables['Build.SourceBranch'], 'refs/heads/main')
    )

  steps:
  - script: echo "Deploying to Production"

How does it work?

Code Pushed
     |
     v
Build Job
     |
     v
Build Successful?
     |
     +---- NO ---> Skip Production Job
     |
     +---- YES
             |
             v
       Is Branch main?
             |
             +---- NO ---> Skip Production Job
             |
             +---- YES
                     |
                     v
              Deploy Production

Important: We combine succeeded() with the branch check to ensure the production job executes only after the build succeeds.

4. Conditional Execution Based on Environment

We can use pipeline parameters to select the target environment.

Example: DEV, UAT, and PROD

parameters:
- name: environment
  displayName: 'Select Environment'
  type: string
  default: dev
  values:
  - dev
  - uat
  - prod

pool:
  vmImage: 'ubuntu-latest'

jobs:
- job: DeployDEV
  condition: eq('${{ parameters.environment }}', 'dev')
  steps:
  - script: echo "Deploying to DEV"

- job: DeployUAT
  condition: eq('${{ parameters.environment }}', 'uat')
  steps:
  - script: echo "Deploying to UAT"

- job: DeployPROD
  condition: eq('${{ parameters.environment }}', 'prod')
  steps:
  - script: echo "Deploying to PROD"

Execution flow

Run Pipeline
     |
     v
Select Environment
     |
     +---- dev
     |      |
     |      v
     |   Execute DeployDEV
     |
     +---- uat
     |      |
     |      v
     |   Execute DeployUAT
     |
     +---- prod
            |
            v
         Execute DeployPROD

Only the job matching the selected environment executes. The other two jobs are skipped.

5. Conditional Execution of Stages

In real-world projects, we generally organize pipelines using multiple stages.

For example:

Pipeline
   |
   v
Build Stage
   |
   v
DEV Stage
   |
   v
UAT Stage
   |
   v
PROD Stage

We can apply conditions at the stage level to control which stages execute.

YAML example

trigger:
- dev
- main

pool:
  vmImage: 'ubuntu-latest'

stages:

# Stage 1 - Build
- stage: Build
  jobs:
  - job: BuildJob
    steps:
    - script: echo "Building Web API"

# Stage 2 - DEV
- stage: DeployDEV
  dependsOn: Build

  condition: and(
    succeeded(),
    eq(variables['Build.SourceBranch'], 'refs/heads/dev')
    )

  jobs:
  - job: DevJob
    steps:
    - script: echo "Deploying to DEV"

# Stage 3 - PROD
- stage: DeployPROD
  dependsOn: Build

  condition: and(
    succeeded(),
    eq(variables['Build.SourceBranch'], 'refs/heads/main')
    )

  jobs:
  - job: ProdJob
    steps:
    - script: echo "Deploying to PROD"

How does it work?

Developer Pushes Code
        |
        v
    Build Stage
        |
        v
   Build Successful?
        |
        +---- NO ---> Deployment Skipped
        |
        +---- YES
                |
                v
           Check Branch
                |
                +---- dev
                |      |
                |      v
                |   DeployDEV Stage
                |
                +---- main
                       |
                       v
                    DeployPROD Stage

Both deployment stages explicitly depend on the Build stage, so the skipped DEV stage does not prevent PROD from running.

6. Combining Multiple Conditions

We can combine conditions using and(), or(), and not().

Example 1: Branch is main AND build succeeded

condition: and(
  succeeded(),
  eq(variables['Build.SourceBranch'], 'refs/heads/main')
  )

Both conditions must be true.

Example 2: Branch is dev OR main

condition: or(
  eq(variables['Build.SourceBranch'], 'refs/heads/dev'),
  eq(variables['Build.SourceBranch'], 'refs/heads/main')
  )

The stage executes when either branch matches.

Example 3: Execute only when the build fails

condition: failed()

Useful for error-handling or diagnostic steps.

Example 4: Always execute a cleanup step

condition: always()

Useful for cleanup and log collection. However, it does not guarantee execution if an agent becomes unavailable or the run is forcibly terminated.

7. Conditions vs YAML Template Expressions

Azure DevOps supports two important approaches to conditional execution.

Feature

Runtime condition

Template expression

Syntax

condition:

${{ if ... }}

Evaluation

Runtime

Template expansion

Behavior

Runs or skips an existing stage/job/step

Includes or excludes YAML structure

Common use

Branch checks, build results

Parameter-based pipeline structure

Runtime condition

steps:
- script: echo "Production"
  condition: eq(variables['Build.SourceBranchName'], 'main')

The step exists in the pipeline but is skipped if the condition is false.

Template expression

parameters:
- name: environment
  type: string
  default: dev

steps:
- ${{ if eq(parameters.environment, 'prod') }}:
  - script: echo "Production Deployment"

The step is included in the expanded pipeline only when the parameter is prod.

Key difference: Runtime conditions skip execution; template expressions determine which YAML elements are included before execution.

8. Important Real-World Considerations

1. Branch conditions do not automatically protect production.

Even if a deployment stage checks for main, production should also use Azure DevOps Environment approvals, checks, and appropriate permissions.

2. Conditions override the default execution condition.

When writing a custom condition, include succeeded() when successful dependency completion is required.

3. Variables set during a job cannot be used in a condition evaluated before that same job starts.

Use output variables and dependencies when passing results between jobs or stages.

4. Pull Request branch behavior is different.

During PR validation, Build.SourceBranch can contain a value such as refs/pull/123/merge, rather than refs/heads/main. Use appropriate PR variables or checks.

9. Interview Questions and Answers

Q1. What is a condition in Azure DevOps?

A condition is an expression that determines whether a stage, job, or step should execute or be skipped.

Q2. How do you deploy only from the main branch?

Use a branch condition:

condition: and(
  succeeded(),
  eq(variables['Build.SourceBranch'], 'refs/heads/main')
  )

Q3. What is the difference between succeeded() and always()?

succeeded() executes only when dependencies succeed. always() attempts execution regardless of success or failure, including cancellation.

Q4. Can we apply conditions to stages, jobs, and steps?

Yes. The condition: property is supported at all three levels.

Q5. How do you execute different deployment stages for DEV, UAT, and PROD?

Use environment parameters or variables with conditions to select the appropriate deployment stage.

Q6. What happens when a condition evaluates to false?

The corresponding stage, job, or step is marked as skipped.

Q7. What is the difference between condition: and ${{ if }}?

condition: controls runtime execution. ${{ if }} controls YAML structure during template expansion.

10. Key Points for Interview

  • Conditions control whether stages, jobs, or steps execute.

  • Use condition: to define execution rules.

  • Use Build.SourceBranch to identify the source branch.

  • Use eq(), and(), and or() to combine conditions.

  • Use succeeded() to require successful dependencies.

  • Use parameters for environment selection.

  • Use ${{ if }} for compile-time conditional YAML.

  • Protect production deployments with environment approvals and checks.

Interview-ready answer

"In Azure DevOps YAML Pipelines, conditions control whether stages, jobs, or steps execute. We use functions such as succeeded(), failed(), eq(), and and() to define execution rules. For example, we can configure a DEV deployment stage to run only when code is pushed to the dev branch and a production deployment stage to run only from main. We can also use pipeline parameters to select environments. In production projects, we combine conditions with environment approvals and branch policies to ensure controlled deployments."

Official documentation: Azure Pipelines Conditions

← Back to Articles