Skip to content

Commit 4961b40

Browse files
Learn Build Service GitHub AppLearn Build Service GitHub App
Learn Build Service GitHub App
authored and
Learn Build Service GitHub App
committed
Merging changes synced from https://github.com/MicrosoftDocs/azure-devops-docs-pr (branch live)
2 parents 95fbc21 + 497d8c9 commit 4961b40

File tree

1 file changed

+84
-68
lines changed

1 file changed

+84
-68
lines changed

docs/pipelines/process/stages.md

Lines changed: 84 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ title: Stages in Azure Pipelines
33
description: Learn how to organize your jobs into stages, define dependencies, and set conditions. Understand how to implement deployment strategies and use YAML or a Classic pipeline to define stages.
44
ms.assetid: FAAD6503-F8CE-4F5D-8C1E-83AF6E903568
55
ms.topic: conceptual
6-
ms.date: 02/16/2024
6+
ms.date: 03/28/2025
77
monikerRange: '<= azure-devops'
88
---
99

10-
# Add stages, dependencies, & conditions
10+
# Add stages, dependencies, and conditions
1111

1212
[!INCLUDE [version-lt-eq-azure-devops](../../includes/version-lt-eq-azure-devops.md)]
1313

14-
A stage is a logical boundary in an Azure DevOps pipeline. Stages can be used to group actions in your software development process (for example, build the app, run tests, deploy to preproduction). Each stage contains one or more jobs.
14+
A stage is a logical boundary in an Azure DevOps pipeline. Stages group actions in your software development process, like building the app, running tests, and deploying to preproduction. Each stage contains one or more jobs.
1515

1616
When you define multiple stages in a pipeline, by default, they run one after the other. Stages can also depend on each other. You can use the `dependsOn` keyword to define [dependencies](#specify-dependencies). Stages also can run based on the result of a previous stage with [conditions](#conditions).
1717

@@ -26,13 +26,13 @@ You can also learn more about how stages relate to parts of a pipeline in the [Y
2626

2727
You can organize pipeline jobs into stages. Stages are the major divisions in a pipeline: build this app, run these tests, and deploy to preproduction are good examples of stages. They're logical boundaries in your pipeline where you can pause the pipeline and perform various checks.
2828

29-
Every pipeline has at least one stage even if you don't explicitly define it. You can also arrange stages into a dependency graph so that one stage runs before another one. There's a limit of 256 jobs for a stage.
29+
Every pipeline has at least one stage, even if you don't explicitly define it. You can also arrange stages into a dependency graph so that one stage runs before another one. A stage can have up to 256 jobs.
3030

3131
::: moniker-end
3232

3333
#### [Classic](#tab/classic/)
3434
Organize the deployment jobs in your release pipeline into stages.
35-
Stages are the major divisions in your release pipeline: run functional tests, deploy to preproduction, and deploy to production are good examples of release stages.
35+
Stages are the major divisions in your release pipeline. Examples include running functional tests, deploying to preproduction, and deploying to production.
3636

3737
<a name="approvals"></a><a name="conditions"></a>
3838
A stage in a release pipeline consists of [jobs](../process/phases.md) and [tasks](../process/tasks.md).
@@ -50,49 +50,72 @@ and [queuing policies](#queuing-policies) control when a release gets deployed t
5050

5151
::: moniker range="<=azure-devops"
5252

53-
In the simplest case, you don't need any logical boundaries in your pipeline. In that case, you don't have to explicitly use the `stage` keyword. You can directly specify the jobs in your YAML file.
53+
In the simplest case, you don't need logical boundaries in your pipeline. For those scenarios, you can directly specify the jobs in your YAML file without the `stages` keyword. For example, if you have a simple pipeline that builds and tests a small application without requiring separate environments or deployment steps, you can define all the jobs directly without using stages.
5454

5555
```yaml
56-
# this has one implicit stage and one implicit job
5756
pool:
5857
vmImage: 'ubuntu-latest'
59-
steps:
60-
- bash: echo "Hello world"
58+
59+
jobs:
60+
- job: BuildAndTest
61+
steps:
62+
- script: echo "Building the application"
63+
- script: echo "Running tests"
6164
```
6265
66+
This pipeline has one implicit stage and two jobs. The `stages` keyword isn't used because there's only one stage.
67+
6368
```yaml
64-
# this pipeline has one implicit stage
6569
jobs:
66-
- job: A
70+
- job: Build
6771
steps:
68-
- bash: echo "A"
72+
- bash: echo "Building"
6973
70-
- job: B
74+
- job: Test
7175
steps:
72-
- bash: echo "B"
76+
- bash: echo "Testing"
7377
```
7478

75-
If you organize your pipeline into multiple stages, you use the `stages` keyword.
79+
To organize your pipeline into multiple stages, use the `stages` keyword. This YAML defines a pipeline with two stages where each stage contains multiple jobs, and each job has specific steps to execute.
7680

7781
```yaml
7882
stages:
7983
- stage: A
84+
displayName: "Stage A - Build and Test"
8085
jobs:
8186
- job: A1
87+
displayName: "Job A1 - build"
88+
steps:
89+
- script: echo "Building the application in Job A1"
90+
displayName: "Build step"
8291
- job: A2
92+
displayName: "Job A2 - Test"
93+
steps:
94+
- script: echo "Running tests in Job A2"
95+
displayName: "Test step"
8396
8497
- stage: B
98+
displayName: "Stage B - Deploy"
8599
jobs:
86100
- job: B1
101+
displayName: "Job B1 - Deploy to Staging"
102+
steps:
103+
- script: echo "Deploying to staging in Job B1"
104+
displayName: "Staging deployment step"
87105
- job: B2
106+
displayName: "Job B2 - Deploy to Production"
107+
steps:
108+
- script: echo "Deploying to production in Job B2"
109+
displayName: "Production deployment step"
88110
```
89111

90-
If you choose to specify a `pool` at the stage level, then all jobs defined in that stage use that pool unless specified at the job-level.
91-
92112
::: moniker-end
93113

94114
::: moniker range="<=azure-devops"
95115

116+
If you specify a `pool` at the stage level, all jobs in that stage use that pool unless the stage is specified at the job level.
117+
118+
96119
```yaml
97120
stages:
98121
- stage: A
@@ -103,24 +126,12 @@ stages:
103126
pool: JobPool
104127
```
105128

106-
The full syntax to specify a stage is:
107-
108-
```yaml
109-
stages:
110-
- stage: string # name of the stage, A-Z, a-z, 0-9, and underscore
111-
displayName: string # friendly name to display in the UI
112-
dependsOn: string | [ string ]
113-
condition: string
114-
pool: string | pool
115-
variables: { string: string } | [ variable | variableReference ]
116-
jobs: [ job | templateReference]
117-
```
118129

119130
::: moniker-end
120131

121132
#### [Classic](#tab/classic/)
122133

123-
To add a stage to your release pipeline, select the release pipeline in **Releases** page, select the action to **Edit** it, and then select the **Pipeline** tab.
134+
To add a stage to your release pipeline, select the release pipeline on the **Releases** page, select **Edit**, and then select the **Pipeline** tab.
124135
While the most important part of defining a stage is the
125136
automation tasks, you can also configure several properties and options
126137
for a stage in a release pipeline. You can:
@@ -129,7 +140,7 @@ for a stage in a release pipeline. You can:
129140
* Designate one user or a
130141
group to be the stage owner. Stage owners get
131142
notified whenever a deployment to that
132-
stage fails. Being a stage owner doesn't automatically come with any permissions.
143+
stage fails. Stage ownership doesn't automatically include permissions.
133144
* Delete the stage from the pipeline.
134145
* Change the order of stages.
135146
* Save a copy of the stage as a [stage template](../release/env-templates.md).
@@ -145,77 +156,82 @@ for a stage in a release pipeline. You can:
145156

146157
::: moniker range="<=azure-devops"
147158

148-
When you define multiple stages in a pipeline, by default, they run sequentially in the order in which you define them in the YAML file. The exception to this is when you add dependencies. With dependencies, stages run in the order of the `dependsOn` requirements.
159+
When you define multiple stages in a pipeline, they run sequentially by default in the order you define them in the YAML file. The exception to this is when you add dependencies. With dependencies, stages run in the order of the `dependsOn` requirements.
149160

150161
Pipelines must contain at least one stage with no dependencies.
151162

152-
The syntax for defining multiple stages and their dependencies is:
163+
For more information on how to define stages, see [stages in the YAML schema](/azure/devops/pipelines/yaml-schema/stages).
153164

154-
```yaml
155-
stages:
156-
- stage: string
157-
dependsOn: string
158-
condition: string
159-
```
165+
The following example stages run sequentially. If you don't use a `dependsOn` keyword, stages run in the order they're defined.
160166

161-
Example stages that run sequentially:
162167

163168
```yaml
164-
# if you do not use a dependsOn keyword, stages run in the order they are defined
165169
stages:
166-
- stage: QA
170+
- stage: Build
171+
displayName: "Build Stage"
167172
jobs:
168-
- job:
169-
...
173+
- job: BuildJob
174+
steps:
175+
- script: echo "Building the application"
176+
displayName: "Build Step"
170177
171-
- stage: Prod
178+
- stage: Test
179+
displayName: "Test Stage"
172180
jobs:
173-
- job:
174-
...
181+
- job: TestJob
182+
steps:
183+
- script: echo "Running tests"
184+
displayName: "Test Step"
175185
```
176186

177187
Example stages that run in parallel:
178188

179189
```yaml
180190
stages:
181191
- stage: FunctionalTest
192+
displayName: "Functional Test Stage"
182193
jobs:
183-
- job:
184-
...
194+
- job: FunctionalTestJob
195+
steps:
196+
- script: echo "Running functional tests"
197+
displayName: "Run Functional Tests"
185198
186199
- stage: AcceptanceTest
187-
dependsOn: [] # this removes the implicit dependency on previous stage and causes this to run in parallel
200+
displayName: "Acceptance Test Stage"
201+
dependsOn: [] # Runs in parallel with FunctionalTest
188202
jobs:
189-
- job:
190-
...
203+
- job: AcceptanceTestJob
204+
steps:
205+
- script: echo "Running acceptance tests"
206+
displayName: "Run Acceptance Tests"
191207
```
192208

193-
Example of fan-out and fan-in:
209+
Example of fan-out and fan-in behavior:
194210

195211
```yaml
196212
stages:
197213
- stage: Test
198214
199215
- stage: DeployUS1
200-
dependsOn: Test # this stage runs after Test
216+
dependsOn: Test # stage runs after Test
201217
202218
- stage: DeployUS2
203-
dependsOn: Test # this stage runs in parallel with DeployUS1, after Test
219+
dependsOn: Test # stage runs in parallel with DeployUS1, after Test
204220
205221
- stage: DeployEurope
206-
dependsOn: # this stage runs after DeployUS1 and DeployUS2
222+
dependsOn: # stage runs after DeployUS1 and DeployUS2
207223
- DeployUS1
208224
- DeployUS2
209225
```
210226

211227
::: moniker-end
212228

213229
#### [Classic](#tab/classic/)
214-
You control the dependencies by setting the triggers on each stage of the release pipeline:
230+
Control dependencies by setting triggers on each stage of the release pipeline:
215231

216-
* Stages run with a trigger or by being manually started.
217-
* With an **After release** trigger, a stage starts as soon as the release starts, in parallel with other stages that have **After release** trigger.
218-
* With an **After stage** trigger, a stage will start after all the dependent stages complete. Using this, you can model fan-out and fan-in behavior for stages.
232+
* Stages run with a trigger or are manually started.
233+
* With an **After release** trigger, a stage starts as soon as the release begins, running in parallel with other stages that have the same trigger.
234+
* With an **After stage** trigger, a stage starts after all dependent stages complete. Using this, you can model fan-out and fan-in behavior for stages.
219235

220236
* * *
221237

@@ -275,12 +291,12 @@ When you specify **After release** or **After stage** triggers, you can also spe
275291

276292
#### [YAML](#tab/yaml/)
277293
::: moniker range="<=azure-devops"
278-
YAML pipelines don't support queuing policies. Each run of a pipeline is independent from and unaware of other runs. In other words, your two successive commits may trigger two pipelines, and both of them will execute the same sequence of stages without waiting for each other. While we work to bring queuing policies to YAML pipelines, we recommend that you use [manual approvals](approvals.md) in order to manually sequence and control the order the execution if this is of importance.
294+
YAML pipelines don't support queuing policies. Each run of a pipeline is independent from and unaware of other runs. In other words, your two successive commits might trigger two pipelines, and both of them will execute the same sequence of stages without waiting for each other. While we work to bring queuing policies to YAML pipelines, we recommend that you use [manual approvals](approvals.md) in order to manually sequence and control the order the execution if this is of importance.
279295
::: moniker-end
280296

281297
#### [Classic](#tab/classic/)
282-
In some cases, you may be able to generate builds faster than
283-
they can be deployed. Alternatively, you may configure multiple
298+
In some cases, you might be able to generate builds faster than
299+
they can be deployed. Alternatively, you might configure multiple
284300
[agents](../agents/agents.md) and, for example, be creating releases from the same release pipeline
285301
for deployment of different artifacts. In such cases, it's useful to
286302
be able to control how multiple releases are queued into a
@@ -370,14 +386,14 @@ In the following example, the development stage runs automatically, while the pr
370386

371387
```yaml
372388
stages:
373-
- stage: development
389+
- stage: Development
374390
displayName: Deploy to development
375391
jobs:
376392
- job: DeployJob
377393
steps:
378394
- script: echo 'hello, world'
379395
displayName: 'Run script'
380-
- stage: production
396+
- stage: Production
381397
displayName: Deploy to production
382398
trigger: manual
383399
jobs:
@@ -389,9 +405,9 @@ stages:
389405

390406
## Mark a stage as unskippable
391407

392-
Mark a stage as `isSkippable: false` to prevent pipeline users from skipping stages. For example, you may have a YAML template that injects a stage that performs malware detection in all pipelines. If you set `isSkippable: false` for this stage, Pipeline won't be able to skip malware detection.
408+
Mark a stage as `isSkippable: false` to prevent pipeline users from skipping stages. For example, you might have a YAML template that injects a stage that performs malware detection in all pipelines. If you set `isSkippable: false` for this stage, your pipeline won't be able to skip malware detection.
393409

394-
In the following example, the Malware detection stage is marked as non-skippable, meaning it must be executed as part of the pipeline run.
410+
In the following example, the Malware detection stage is marked as nonskippable, meaning it must be executed as part of the pipeline run.
395411

396412
```yaml
397413
- stage: malware_detection
@@ -402,7 +418,7 @@ In the following example, the Malware detection stage is marked as non-skippable
402418
...
403419
```
404420

405-
When a stage is non-skippable, it will show with a disabled checkbox in the **Stages to run** configuration panel.
421+
When a stage is nonskippable, it shows with a disabled checkbox in the **Stages to run** configuration panel.
406422

407423
:::image type="content" source="media/stages/stages-run-skip-stage.png" alt-text="Screenshot of stages to run with disabled stage. ":::
408424

0 commit comments

Comments
 (0)