Back to Blog
2 min read

Azure DevOps Pipeline Templates: Reusable CI/CD

Pipeline templates enable reusable, standardized CI/CD across projects. Define once, use everywhere—with parameters for customization.

Template Types

  • Stage templates: Reusable stages
  • Job templates: Reusable jobs
  • Step templates: Reusable steps
  • Variable templates: Shared variables

Step Template

# templates/build-dotnet.yml
parameters:
  - name: projectPath
    type: string
  - name: buildConfiguration
    type: string
    default: 'Release'

steps:
  - task: DotNetCoreCLI@2
    displayName: 'Restore packages'
    inputs:
      command: 'restore'
      projects: '${{ parameters.projectPath }}'

  - task: DotNetCoreCLI@2
    displayName: 'Build'
    inputs:
      command: 'build'
      projects: '${{ parameters.projectPath }}'
      arguments: '--configuration ${{ parameters.buildConfiguration }} --no-restore'

  - task: DotNetCoreCLI@2
    displayName: 'Test'
    inputs:
      command: 'test'
      projects: '${{ parameters.projectPath }}'
      arguments: '--configuration ${{ parameters.buildConfiguration }} --no-build'

Using Step Template

# azure-pipelines.yml
trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - template: templates/build-dotnet.yml
    parameters:
      projectPath: 'src/MyApp/MyApp.csproj'
      buildConfiguration: 'Release'

Job Template

# templates/deploy-webapp.yml
parameters:
  - name: environment
    type: string
  - name: azureSubscription
    type: string
  - name: appName
    type: string

jobs:
  - deployment: Deploy
    displayName: 'Deploy to ${{ parameters.environment }}'
    environment: ${{ parameters.environment }}
    strategy:
      runOnce:
        deploy:
          steps:
            - download: current
              artifact: drop

            - task: AzureWebApp@1
              displayName: 'Deploy to Azure Web App'
              inputs:
                azureSubscription: '${{ parameters.azureSubscription }}'
                appType: 'webApp'
                appName: '${{ parameters.appName }}'
                package: '$(Pipeline.Workspace)/drop/**/*.zip'

Stage Template

# templates/stage-deploy.yml
parameters:
  - name: stageName
    type: string
  - name: environment
    type: string
  - name: dependsOn
    type: object
    default: []

stages:
  - stage: ${{ parameters.stageName }}
    displayName: 'Deploy to ${{ parameters.environment }}'
    dependsOn: ${{ parameters.dependsOn }}
    jobs:
      - template: deploy-webapp.yml
        parameters:
          environment: ${{ parameters.environment }}
          azureSubscription: 'MyAzureConnection'
          appName: 'myapp-${{ parameters.environment }}'

Complete Pipeline with Templates

# azure-pipelines.yml
trigger:
  - main

variables:
  - template: templates/variables.yml

stages:
  - stage: Build
    jobs:
      - job: BuildJob
        pool:
          vmImage: 'ubuntu-latest'
        steps:
          - template: templates/build-dotnet.yml
            parameters:
              projectPath: '**/*.csproj'

          - task: PublishBuildArtifacts@1
            inputs:
              pathtoPublish: '$(Build.ArtifactStagingDirectory)'
              artifactName: 'drop'

  - template: templates/stage-deploy.yml
    parameters:
      stageName: DeployDev
      environment: 'development'
      dependsOn: ['Build']

  - template: templates/stage-deploy.yml
    parameters:
      stageName: DeployStaging
      environment: 'staging'
      dependsOn: ['DeployDev']

  - template: templates/stage-deploy.yml
    parameters:
      stageName: DeployProd
      environment: 'production'
      dependsOn: ['DeployStaging']

Variable Templates

# templates/variables.yml
variables:
  buildConfiguration: 'Release'
  dotnetVersion: '6.0.x'
  azureSubscription: 'MyAzureServiceConnection'

Extending Templates

# Base template with required structure
# templates/base-pipeline.yml
parameters:
  - name: customSteps
    type: stepList
    default: []

stages:
  - stage: Build
    jobs:
      - job: Build
        steps:
          - checkout: self
          - ${{ parameters.customSteps }}
          - task: PublishBuildArtifacts@1

Templates transform pipeline chaos into maintainable, standardized CI/CD.

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.