Skip to content

Getting Started with Azure DevOps Pipelines: From Hello World to Real-World Deployments

Learn how to build and deploy Azure DevOps Pipelines, from a simple "Hello World" to real-world multi-job deployments.

Hello-World Pipeline

Azure DevOps YAML Pipeline to Print "Hello World"

azure-pipelines.yml
# Basic Azure DevOps Pipeline YAML to print "Hello World"

# 'trigger' defines which branch will trigger the pipeline automatically.
trigger:
  - main  # (1)!

# 'pool' specifies the agent (virtual machine) where the pipeline will run.
pool:
  vmImage: ubuntu-latest  # (2)!

# 'steps' define the tasks the pipeline will execute.
steps:
  - script: echo "Hello World from Azure DevOps!" # (3)!
    displayName: 'Print Hello World'  
  1. trigger — Start the Pipeline Automatically. The trigger field specifies the branch that kicks off the pipeline.

    • main

    • development

    • feature1

    • feature2

  2. pool — Choose an Agent. The pool defines where the pipeline runs.

    • ubuntu-latest uses a ready-to-go Ubuntu machine provided by Microsoft.

    • windows-latest

    • macos-latest

  3. steps — Define the Tasks. steps list the actions the agent should perform.

    • script: echo "Hello World..." simply runs a command to print a message in the pipeline logs.

    • script: run main.py #Run Python Script

    • script: Any other "Commands Here"

📌 Summary:

Concept Description
trigger Tells when to run (based on branch).
pool Tells where to run (which agent image).
steps Tells what to run (the actual commands).

Variables

Inline variables inside YAML

azure-pipelines.yml
# Azure DevOps Pipeline to print Hello World using variables

trigger:
  - main

variables:
  greeting: "Hello World from Azure DevOps with Variables!"

pool:
  vmImage: ubuntu-latest

steps:
  - script: echo $(greeting) #Calling Variable
    displayName: 'Print Hello World using Variable'

Using External Variables in Azure DevOps Pipeline

Earlier, we learned how to define variables inside the YAML file itself.
Now, let's take the next step and separate variables cleanly.

  • Version 1: Using a file to store variables.

  • Version 2: Using a Variable Group from Azure DevOps Library.

Loading Variable from a File (for example, variables/vars.txt) and use it inside our pipeline.

  • Create a file in your Repo in this location variables/vars.txt

mkdir -p variables/vars.txt
* Paste the below content
azure-pipelines.yml
variables:
greeting: "Hello World from Template!"

  • Create the Main Pipeline YAML
azure-pipelines.yml
trigger:
- main

# Load variables from an external YAML file
variables:
- template: variables/vars.yml  # Load greeting variable from variables/vars.yml

pool:
vmImage: ubuntu-latest

steps:
- script: echo $(greeting)
    displayName: 'Print Hello World from Template Variable'

This time, we will create a Variable Group from the Azure DevOps UI and use it inside the pipeline.

  • Create a Variable Group

  • Go to Azure DevOps PortalPipelinesLibrary+ Variable group

  • Create a group named (for example): hello-world-vars
  • Add a variable:
  • Name: greeting
  • Value: Hello World from Variable Group!

✅ Save it.

  • Create the Main Pipeline YAML
azure-pipelines.yml
trigger:
- main
# Load variables from Azure DevOps Variable Groups
variables:
- group: hello-world-vars 

pool:
vmImage: ubuntu-latest

steps:
- script: echo $(greeting)
    displayName: 'Print Hello World from Variable Group'

Pre-defined Variables

Pre-defined variables in Azure DevOps are automatically available during pipeline execution. These variables provide useful information about the pipeline's execution environment, build system, and process details. These variables can be used in pipeline definitions to access dynamic data, such as paths, build numbers, and agent details.

Working Directory Variables

Variable Name Description Example Value
$(Build.SourcesDirectory) The directory where the source code is checked out. /home/vsts/work/1/s
$(Build.ArtifactStagingDirectory) The directory where build artifacts are staged before being published. /home/vsts/work/1/a
$(Build.BinariesDirectory) The directory where build output (binaries) are stored. /home/vsts/work/1/b
$(Build.DropDirectory) The directory for the final drop of artifacts or outputs. /home/vsts/work/1/d

Artifact Variables

Variable Name Description Example Value
$(Build.ArtifactStagingDirectory) The directory where the build artifacts are staged before being published. /home/vsts/work/1/a
$(Build.ArtifactName) The name of the artifact being published. myArtifact.zip
$(Build.BuildId) A unique ID of the current build. 12345
$(Build.DefinitionName) The name of the build definition. BuildPipeline

Agent/System Variables

Variable Name Description Example Value
$(Agent.HomeDirectory) The home directory of the agent on the machine. /home/vsts/agent
$(Agent.OS) The operating system of the agent. Linux
$(Agent.WorkFolder) The directory used by the agent to store temporary files. /home/vsts/work
$(Agent.TempDirectory) The temporary directory for the agent during builds. /home/vsts/temp
$(Pipeline.Workspace) The workspace directory where pipeline data is stored. /home/vsts/work/1/s
$(Pipeline.BuildId) The unique identifier of the current build. 12345

Build and Release Variables

Variable Name Description Example Value
$(Build.BuildId) A unique ID for the current build. 12345
$(Build.DefinitionName) The name of the build pipeline definition. CI-CD Pipeline
$(Build.SourceBranch) The source branch for the current build. refs/heads/main
$(Build.Repository.Name) The name of the repository associated with the build. MyRepo
$(Release.ReleaseId) The unique identifier of the release. 98765
$(Release.EnvironmentName) The name of the environment in the release pipeline. Production

Note

For more details on available variables in Azure DevOps, please refer to the official Microsoft documentation.

Agent Workspace Path: /home/vsts/work/s/a Breakdown

Full Path Component Description Example Value
/home/vsts/ The base directory for the agent. /home/vsts/
/work/ The working directory where the agent works. /home/vsts/work/
/1/ A unique number identifying a specific build. /home/vsts/work/1/
/s/ The source code directory where your repository is checked out. /home/vsts/work/1/s/

Sample Pipeline

azure-pipelines.yml
trigger:
  - main

pool:
  vmImage: ubuntu-latest

steps:
  - checkout: self  # Checkout the code from the main branch of the Azure Repo

  - script: |
      echo "Listing files in $(Build.SourcesDirectory):"
      ls $(Build.SourcesDirectory)  # List all files in the source directory
    displayName: 'List Files from Repo'

Environment

Environment in Azure DevOps is a way to define a target place (like Dev, QA, Prod servers) where you deploy your application and control approvals, checks, history, etc.

Creating Environment

  • Go to Azure DevOps → Pipelines → Environments.
  • Create a New Environment (example: Dev-Environment).
  • Inside that Environment, go to Approvals and Checks.
  • Add an Approval → Example: Add yourself or your team to approve.

⚡ Super Simple Flow:

Code Push  Pipeline Trigger  Environment Approval Needed  Approver Clicks "Approve"  Pipeline Continues
azure-pipelines.yml
trigger:
  - main

variables:
  - template: variables/vars.yml  # Load greeting variable from variables/vars.yml

pool:
  vmImage: ubuntu-latest

# Link this pipeline to an Environment
environment: Dev-Environment   # Specify the environment name 

# Define the steps
steps:
  - script: echo $(greeting)
    displayName: 'Print Hello World from Template Variable'

Info

✅ You can attach your pipeline to an Environment, and then configure approvals (like someone must manually approve) before the pipeline can proceed.


Jobs

  • A job is a collection of steps that run together on the same agent.
  • Each job gets its own clean machine (agent).
  • If you have multiple jobs, they can run parallel or sequential based on how you design.
  • Jobs help organize tasks like "Build", "Test", "Deploy" into separate logical blocks.

⚡ Super Simple Flow:

Job Start  Step 1  Step 2  Step "n"  Job End
azure-pipelines.yml
trigger:
  - main

variables:
  - template: variables/vars.yml  # Load greeting variable from external file

pool:
  vmImage: ubuntu-latest

jobs:
  - job: PrintJob  # Define a Job named 'PrintJob'
    displayName: 'Print Greeting Job'
    environment: Dev-Environment  # Attach Environment directly to Job ✅

    steps:  # Steps inside the Job
      - script: echo $(greeting)
        displayName: 'Print Hello World from Template Variable'
azure-pipelines.yml
trigger:
  - main

variables:
  - template: variables/vars.yml  # Load variables from external template

pool:
  vmImage: ubuntu-latest

jobs:
  - job: BuildJob
    displayName: 'Build Job'
    environment: Dev-Environment  # Attach Environment directly to the Build job
    steps:
      - script: |
          echo $(greeting)  # Use the greeting variable from the template
          echo "Building the project..."
        displayName: 'Run Build Steps'

  - job: DeployJob
    displayName: 'Deploy Job'
    dependsOn: BuildJob  # This job depends on 'BuildJob'
    environment: Dev-Environment  # Attach the same environment to Deploy job (can be different too)
    steps:
      - script: |
          echo $(greeting)  # Use the greeting variable again
          echo "Deploying the project..."
        displayName: 'Run Deployment Steps'

Info

If you have only a single dependency (example: dependsOn a single job like dependsOn: BuildJob), you can skip square brackets and just write it directly without [ ].

azure-pipelines.yml
trigger:
  - main

variables:
  - template: variables/vars.yml  # Load variables from external template

pool:
  vmImage: ubuntu-latest

jobs:
  - job: BuildJob
    displayName: 'Build Job'
    environment: Dev-Environment  # Attach Environment directly to the Build job
    steps:
      - script: |
          echo $(greeting)  # Use the greeting variable from the template
          echo "Building the project..."
        displayName: 'Run Build Steps'

  - job: TestJob
    displayName: 'Test Job'
    dependsOn: BuildJob  # This job depends on 'BuildJob'
    environment: Test-Environment  # Attach a different environment to the Test job
    steps:
      - script: |
          echo $(greeting)  # Use the greeting variable again
          echo "Running tests..."
        displayName: 'Run Test Steps'

  - job: DeployJob
    displayName: 'Deploy Job'
    dependsOn: [BuildJob, TestJob]  # This job depends on both 'BuildJob' and 'TestJob'
    environment: Test-Environment  # Attach the Test environment to Deploy job
    steps:
      - script: |
          echo $(greeting)  # Use the greeting variable again
          echo "Deploying the project..."
        displayName: 'Run Deployment Steps'

Info

When you have multiple dependencies (example: dependsOn multiple jobs like dependsOn: [BuildJob, TestJob]), you must use square brackets [ ] to list them.

📌 Summary:

Concept Description
Steps Small tasks (scripts, copy files, etc.)
Job A collection of steps
Environment Can be attached at the Job level too if needed
dependsOn Usage Use [ ] when depending on multiple jobs, no [ ] needed for single job

Stages

A stage in Azure DevOps is like a big chapter inside your pipeline.

Each stage groups related steps together.
Example: - One stage for building your code (Build stage) - Another stage for deploying your app (Deploy stage)

✅ Stages help you organize your pipeline.
✅ You can also control approvals, conditions, and flows between stages.

In Simple Terms

If Build succeeds ➔ then go to Deploy after approval.

⚡ Super Simple Flow:

Trigger  Build Stage  Deploy Stage (Approval)  Done
azure-pipelines.yml
trigger:
- main

# Load variables from external file
variables:
- template: variables/vars.yml

# Use Ubuntu agent
pool:
  vmImage: ubuntu-latest

# Define stages
stages:
- stage: Build
  displayName: 'Build Stage'
  jobs:
  - job: BuildJob
    displayName: 'Run Build Job'
    steps:
    - script: echo "Building project..."
      displayName: 'Build Step'
    - script: echo $(greeting)
      displayName: 'Print Greeting Message'

- stage: Deploy
  displayName: 'Deploy Stage'
  dependsOn: Build # wait for build to complete
  jobs:
  - job: DeployJob
    displayName: 'Run Deploy Job'
    environment: Dev-Environment  # Add Approval Here ✅
    steps:
    - script: echo "Deploying to server..."
      displayName: 'Deployment Step'

📌 Summary:

Concept Description
Steps Small tasks (scripts, copy files, etc.)
Job A collection of steps
Stages A collection of jobs, representing a larger unit of work
Environment Can be attached at the Job level too if needed