1. What are Output Variables in Azure DevOps?
In Azure DevOps YAML Pipelines, output variables allow us to pass values generated during pipeline execution from one step, job, or stage to another.
For example, suppose an ASP.NET Core Web API pipeline has three stages:
-
Build: Builds the application and generates a version number.
-
UAT: Uses the generated version number during deployment.
-
Production: Uses the same version number for production deployment.
Instead of hardcoding the version number, we can generate it during the Build stage and pass it to subsequent stages.
How does it work?
Azure Pipeline
|
v
Build Stage
|
| Generate Version = 1.0.25
|
v
Set Output Variable
|
| appVersion = 1.0.25
|
v
UAT Stage
|
| Read appVersion
| Deploy Version 1.0.25
|
v
Production Stage
|
| Read appVersion
| Deploy Version 1.0.25
|
v
Pipeline Completed
Important: Variables are not automatically shared across all jobs and stages. We must use output variables and dependency expressions to access values across execution boundaries.
2. How to Set an Output Variable
Azure DevOps provides a special logging command:
##vso[task.setvariable variable=variableName;isOutput=true]value
Example:
steps:
- bash: |
echo "##vso[task.setvariable variable=appVersion;isOutput=true]1.0.25"
name: SetVersion
Explanation:
|
Property |
Description |
|---|---|
|
|
Creates or updates a pipeline variable |
|
|
Variable name |
|
|
Marks the variable as an output |
|
|
Variable value |
|
|
Step reference name used by downstream consumers |
The name property is important because other jobs or stages use it to identify the output.
3. Passing Variables Between Steps in the Same Job
When steps belong to the same job, passing values is straightforward.
Example
jobs:
- job: BuildJob
steps:
- bash: |
echo "##vso[task.setvariable variable=appVersion]1.0.25"
displayName: 'Set Version'
- bash: |
echo "Application Version: $(appVersion)"
displayName: 'Display Version'
Output:
Application Version: 1.0.25
How does it work?
BuildJob
|
v
Step 1: Generate Version
|
| appVersion = 1.0.25
|
v
Step 2: Read Version
|
| $(appVersion)
|
v
Output: 1.0.25
Here, isOutput=true is not required because both steps belong to the same job.
The updated variable becomes available to subsequent steps, not earlier steps or the same script process that sets it.
4. Passing Output Variables Between Jobs
Suppose we have two jobs:
-
BuildJobgenerates the application version. -
DeployJobreads the version.
We use dependencies to access output variables from another job.
YAML example
jobs:
# Job 1: Generate Version
- job: BuildJob
steps:
- bash: |
echo "##vso[task.setvariable variable=appVersion;isOutput=true]1.0.25"
name: SetVersion
# Job 2: Read Version
- job: DeployJob
dependsOn: BuildJob
variables:
versionFromBuild: $[ dependencies.BuildJob.outputs['SetVersion.appVersion'] ]
steps:
- bash: |
echo "Deploying Version: $(versionFromBuild)"
Explanation
Step 1: BuildJob generates appVersion = 1.0.25.
Step 2: SetVersion identifies the step that produces the output.
Step 3: DeployJob depends on BuildJob.
Step 4: The following expression reads the output:
$[ dependencies.BuildJob.outputs['SetVersion.appVersion'] ]
Step 5: The output is assigned to a local variable named versionFromBuild.
Step 6: DeployJob accesses the variable using:
$(versionFromBuild)
Execution flow
BuildJob
|
| Generate appVersion = 1.0.25
|
v
SetVersion Step
|
| isOutput=true
|
v
BuildJob Completed
|
v
DeployJob
|
| dependsOn: BuildJob
|
v
Read Output Using dependencies
|
| versionFromBuild = 1.0.25
|
v
Deploy Version 1.0.25
Key point: To access output variables from another job in the same stage, use:
$[ dependencies.JobName.outputs['StepName.VariableName'] ]
5. Passing Output Variables Between Stages
In enterprise applications, pipelines usually contain multiple stages.
For example:
Build Stage
|
v
UAT Stage
|
v
Production Stage
To pass output variables between stages, we use stageDependencies.
YAML example
stages:
# Stage 1: Build
- stage: Build
jobs:
- job: BuildJob
steps:
- bash: |
echo "##vso[task.setvariable variable=appVersion;isOutput=true]1.0.25"
name: SetVersion
# Stage 2: UAT
- stage: UAT
dependsOn: Build
jobs:
- job: DeployUAT
variables:
versionFromBuild: $[ stageDependencies.Build.BuildJob.outputs['SetVersion.appVersion'] ]
steps:
- bash: |
echo "Deploying Version: $(versionFromBuild)"
Explanation
The Build stage generates the application version.
The UAT stage depends on the Build stage and reads its output using:
$[ stageDependencies.Build.BuildJob.outputs['SetVersion.appVersion'] ]
|
Part |
Meaning |
|---|---|
|
|
Source stage name |
|
|
Source job name |
|
|
Step that created the output |
|
|
Output variable name |
Execution flow
Build Stage
|
v
BuildJob
|
| Generate appVersion = 1.0.25
|
v
SetVersion Step
|
| Set Output Variable
|
v
Build Stage Completed
|
v
UAT Stage
|
| dependsOn: Build
|
v
DeployUAT Job
|
| Read stageDependencies
|
v
Deploy Version 1.0.25
Important: Output variables are intended for downstream stages. If a stage needs an output from an earlier, non-immediately preceding stage, explicitly include the source stage in dependsOn.
6. Complete Example: Build → UAT → Production
Let's create a simplified ASP.NET Core deployment pipeline that generates an application version and passes it to both UAT and Production.
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
stages:
# Stage 1: Build
- stage: Build
jobs:
- job: BuildJob
steps:
- bash: |
echo "Building Web API"
echo "##vso[task.setvariable variable=appVersion;isOutput=true]1.0.25"
name: SetVersion
# Stage 2: UAT
- stage: UAT
dependsOn: Build
jobs:
- job: DeployUAT
variables:
appVersion: $[ stageDependencies.Build.BuildJob.outputs['SetVersion.appVersion'] ]
steps:
- bash: |
echo "UAT Deployment Version: $(appVersion)"
# Stage 3: Production
- stage: Production
dependsOn:
- Build
- UAT
jobs:
- job: DeployProduction
variables:
appVersion: $[ stageDependencies.Build.BuildJob.outputs['SetVersion.appVersion'] ]
steps:
- bash: |
echo "Production Deployment Version: $(appVersion)"
How does it work?
Developer Pushes Code
|
v
Build Stage
|
| Generate appVersion = 1.0.25
|
v
BuildJob Completed
|
v
UAT Stage
|
| Read Build Output
| Version = 1.0.25
|
v
UAT Completed
|
v
Production Stage
|
| Read Build Output
| Version = 1.0.25
|
v
Pipeline Completed
Both deployment stages explicitly depend on the Build stage, and Production also depends on UAT.
This example demonstrates output-variable passing. It does not perform actual application deployment. In a production pipeline, the same build artifact should be promoted across environments rather than rebuilding separately.
7. Difference Between dependencies and stageDependencies
This is an important Azure DevOps interview question.
|
Feature |
|
|
|---|---|---|
|
Purpose |
Access dependency results and outputs |
Access outputs from jobs in previous stages |
|
Same-stage job output |
Yes |
No |
|
Cross-stage output |
Yes, in stage-level conditions |
Yes, for mapping outputs into variables |
|
Common usage |
Job-to-job values, conditions |
Stage-to-stage variable passing |
Job-to-job syntax
$[ dependencies.BuildJob.outputs['SetVersion.appVersion'] ]
Stage-to-stage syntax
$[ stageDependencies.Build.BuildJob.outputs['SetVersion.appVersion'] ]
Cross-stage condition syntax
For a condition on a stage, the common syntax is:
condition: eq(dependencies.Build.outputs['BuildJob.SetVersion.appVersion'], '1.0.25')
This differs from the expression used to map an output into a job variable.
8. Important Considerations
1. Use isOutput=true for cross-job and cross-stage outputs.
Without it, the value is not exposed using the output-variable dependency syntax.
2. Give the producing step a name.
name: SetVersion
This allows downstream jobs to reference the output reliably.
3. Use runtime expressions to map output variables.
variables:
appVersion: $[ dependencies.BuildJob.outputs['SetVersion.appVersion'] ]
4. Use dependsOn to establish dependencies.
A downstream job or stage must have the appropriate dependency relationship to access the output.
5. Do not use ordinary output variables for large data.
For large files, deployment packages, or build outputs, use Pipeline Artifacts instead.
6. Avoid exposing sensitive information.
Use secret variables, secure files, Azure Key Vault, or other approved secret-management mechanisms rather than printing secrets in scripts.
9. Interview Questions and Answers
Q1. What is an output variable in Azure DevOps?
An output variable is a value generated by a pipeline step that can be accessed by downstream steps, jobs, or stages.
Q2. How do you create an output variable?
Using the task.setvariable logging command with isOutput=true.
echo "##vso[task.setvariable variable=version;isOutput=true]1.0"
Q3. How do you pass variables between jobs?
Use isOutput=true in the producing step and access the output using dependencies.
Q4. How do you pass variables between stages?
Use stageDependencies to map an output variable from a previous stage into the consuming job.
Q5. What is the purpose of dependsOn?
It defines execution dependencies between jobs or stages, controlling ordering and establishing relationships needed to access outputs.
Q6. Can a variable generated in the Build stage be used in Production?
Yes. The Production stage can access the Build stage output when the appropriate dependency relationship exists.
Q7. What is the difference between pipeline variables and output variables?
Pipeline variables store configuration values, while output variables specifically expose values generated during execution to downstream consumers.
Q8. Can we pass files between jobs using output variables?
No. Output variables are suitable for small text values. Use Pipeline Artifacts to transfer files between jobs or stages.
10. Key Points for Interview
-
Same job: Use
$(variableName)in subsequent steps. -
Different jobs: Use
dependencies. -
Different stages: Use
stageDependencies. -
Output variable: Set
isOutput=true. -
Step name: Required for referencing named output variables.
-
Execution order: Use
dependsOn. -
Files and packages: Use Pipeline Artifacts rather than output variables.
Interview-ready answer
"In Azure DevOps YAML Pipelines, we use output variables to pass dynamically generated values between jobs and stages. We create an output variable using the task.setvariable logging command with isOutput=true. To access an output from another job in the same stage, we use the dependencies expression. To access outputs across stages, we commonly use stageDependencies. We also configure dependsOn to establish the required execution order. For example, a Build stage can generate an application version and pass it to UAT and Production deployment stages, ensuring both use the same version."
Official documentation: Set Variables in Scripts — Microsoft Learn