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 |
|---|---|
|
|
Runs when dependencies succeed |
|
|
Runs when dependencies fail |
|
|
Runs regardless of success or failure, including cancellation where possible |
|
|
Runs after success or failure, but not cancellation |
|
|
Checks whether two values are equal |
|
|
Checks whether two values are different |
|
|
Both conditions must be true |
|
|
At least one condition must be true |
|
|
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 |
|---|---|
|
|
|
|
|
|
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 |
|
|
|
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.SourceBranchto identify the source branch. -
Use
eq(),and(), andor()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