Job execution order, parallelism and multi-stage pipelines
Design and implement a strategy for job execution order
The asymmetry that decides most questions
Jobs in a stage run in parallel by default. Stages run sequentially by default, in the order they are defined.
Two different defaults, two different keywords to change them:
stages:
- stage: Build
- stage: IntegrationTest
dependsOn: Build
- stage: FunctionalTest
dependsOn: Build # runs after Build...
- stage: SecurityScan
dependsOn: [] # ...and THIS runs in parallel with everythingdependsOn: [] — an explicitly empty list — is how you opt a stage out of the
implicit sequential chain. Omitting dependsOn entirely does the opposite: the
stage waits for the previous one.
For jobs the reverse holds. Omitting dependsOn means "start immediately";
adding it imposes order.
Fan-out and fan-in
- job: Publish
dependsOn: [Lint, UnitTest, IntegrationTest]
condition: succeeded()A job listing several dependencies waits for all of them.
Matrix
strategy:
matrix:
linux: { imageName: ubuntu-latest }
windows: { imageName: windows-latest }
mac: { imageName: macOS-latest }
maxParallel: 2Two constraints worth memorising:
parallelandmatrixare mutually exclusive — you cannot use both in one strategy block.maxParallelis only valid withmatrix.
Matrix multiplies one job definition into legs; maxParallel throttles how many
legs run at once, which matters when your parallel-job allocation is finite.
Primary sources