Azure DevOps¶
Microsoft's enterprise DevOps platform. Pipelines for CI/CD, Repos for git, Boards for work tracking, Artifacts for packages, Test Plans for QA. Better for Windows/.NET shops, more features than GitHub for enterprise workflows.
2026 Update
Azure Pipelines supports GitHub integration natively. Multi-stage YAML pipelines are standard. Artifact feeds now include npm, NuGet, Maven, Python. Boards integrate with Microsoft Teams. Free tier includes 1800 pipeline minutes/month.
Quick Hits¶
# Azure DevOps CLI (az devops)
az devops configure --defaults organization=https://dev.azure.com/myorg project=MyProject
# Pipelines
az pipelines create --name MyPipeline --yml-path azure-pipelines.yml # (1)!
az pipelines list
az pipelines run --name MyPipeline
az pipelines runs list
az pipelines show --id 123
# Repos
az repos list
az repos create --name MyRepo
az repos policy list --branch main # (2)!
# Pull requests
az repos pr create --title "Feature" --source-branch feature --target-branch main
az repos pr list
az repos pr update --id 456 --status completed
# Boards (work items)
az boards work-item create --title "Bug fix" --type Bug
az boards work-item show --id 789
az boards work-item update --id 789 --state Resolved
# Artifacts (package feeds)
az artifacts universal publish \
--organization https://dev.azure.com/myorg \
--project MyProject \
--scope project \
--feed MyFeed \
--name MyPackage \
--version 1.0.0 \
--path ./dist # (3)!
# Service connections (for deployments)
az devops service-endpoint create \
--service-endpoint-type azurerm \
--name MyAzureConnection
- Creates pipeline from YAML file in repo
- Branch policies enforce PR reviews, build validation
- Universal packages for any file type (not just npm/nuget)
Real talk:
- Azure Pipelines beats GitHub Actions for complex enterprise workflows
- Free tier: 1 parallel job, 1800 minutes/month (more generous than GitHub)
- Self-hosted agents avoid cloud costs (Linux, Windows, macOS)
- Boards integration with work items better than GitHub Projects
- YAML pipelines required (classic UI pipelines deprecated)
# Azure Pipelines YAML (azure-pipelines.yml)
trigger:
branches:
include:
- main
- develop
paths:
exclude:
- docs/* # (1)!
pool:
vmImage: 'ubuntu-latest' # (2)!
variables:
buildConfiguration: 'Release'
stages:
- stage: Build
jobs:
- job: BuildJob
steps:
- task: UseDotNet@2
inputs:
version: '8.x'
- task: DotNetCoreCLI@2
displayName: 'dotnet restore'
inputs:
command: restore
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'dotnet build'
inputs:
command: build
projects: '**/*.csproj'
arguments: '--configuration $(buildConfiguration)'
- task: DotNetCoreCLI@2
displayName: 'dotnet test'
inputs:
command: test
projects: '**/*Tests.csproj'
arguments: '--configuration $(buildConfiguration) --collect:"XPlat Code Coverage"'
- task: PublishCodeCoverageResults@1 # (3)!
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: '$(Agent.TempDirectory)/**/*.cobertura.xml'
- task: DotNetCoreCLI@2
displayName: 'dotnet publish'
inputs:
command: publish
publishWebProjects: true
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)'
- publish: $(Build.ArtifactStagingDirectory) # (4)!
artifact: drop
- stage: Deploy
dependsOn: Build
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) # (5)!
jobs:
- deployment: DeployJob
environment: 'Production' # (6)!
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: drop
- task: AzureWebApp@1
inputs:
azureSubscription: 'MyAzureConnection'
appName: 'my-web-app'
package: '$(Pipeline.Workspace)/drop/**/*.zip'
- Skip CI builds for documentation changes
- Microsoft-hosted agents: ubuntu-latest, windows-latest, macos-latest
- Code coverage reports integrated into Azure DevOps UI
- Publish artifacts for use in deployment stages
- Deploy only on main branch after successful build
- Environment with approval gates and deployment history
# Multi-stage pipeline with templates
# File: azure-pipelines.yml
trigger:
- main
stages:
- template: templates/build.yml
parameters:
buildConfiguration: 'Release'
- template: templates/deploy.yml
parameters:
environment: 'Staging'
- template: templates/deploy.yml
parameters:
environment: 'Production'
# File: templates/build.yml
parameters:
- name: buildConfiguration
type: string
default: 'Release'
stages:
- stage: Build
jobs:
- job: BuildJob
steps:
- script: echo "Building with ${{ parameters.buildConfiguration }}"
# ... build steps
Why this works:
- Multi-stage pipelines with approval gates for production
- Templates reduce duplication across pipelines
- Artifacts persist between stages (build once, deploy many)
- Environment tracking shows deployment history
- Integration with Azure services (App Service, AKS, Functions)
Best Practices
- YAML pipelines only - Classic UI pipelines deprecated
- Pipeline templates - Reuse common steps across pipelines
- Variable groups - Share secrets across multiple pipelines
- Service connections - Scoped credentials for Azure/AWS/K8s
- Environments - Approval gates, deployment history
- Branch policies - Require PR reviews, build validation, work item linking
- Artifact feeds - Upstream sources (npmjs, nuget.org) with caching
Security
- Service connections - Limit scope to specific resource groups
- Variable groups - Mark sensitive values as secret
- Branch protection - Require PR reviews, prevent force-push
- Pipeline permissions - Limit which pipelines can use service connections
- Agent pools - Self-hosted agents need security hardening
- Audit logs - Track who changed what in organization settings
Performance
- Self-hosted agents - Faster for large repos, avoid queue time
- Parallel jobs - Free tier: 1 parallel job, paid: unlimited
- Artifact caching - Cache npm/nuget packages between runs
- Shallow clone - Reduce checkout time with
fetchDepth: 1 - Matrix strategy - Test multiple configurations in parallel
Gotchas
- YAML syntax - Indentation errors common (use VS Code extension)
- Pipeline minutes - 1800 free/month, then $40/parallel job/month
- Service connection expiry - Azure service principals expire (renew annually)
- Classic pipelines - Don't use (deprecated, YAML only)
- Work item linking - Required by default in branch policies (configure exceptions)
- Artifact retention - Default 30 days, configure longer for releases
- Cross-org PRs - Not supported (unlike GitHub forks)
Learning Resources¶
Official Docs¶
- Azure DevOps Documentation - Complete reference
- Azure Pipelines YAML Schema - Syntax reference
- Azure DevOps CLI - Command-line reference
Key Components¶
- Azure Pipelines - CI/CD with YAML or classic (use YAML)
- Azure Repos - Git repositories with branch policies
- Azure Boards - Work tracking (Agile, Scrum, CMMI templates)
- Azure Artifacts - Package feeds (npm, NuGet, Maven, Python, universal)
- Azure Test Plans - Manual and exploratory testing (requires paid license)
Related Tools¶
- Azure CLI with DevOps extension - Command-line automation
- Azure Pipelines VS Code extension - YAML IntelliSense
- Azure Repos VS Code extension - Git integration
Last Updated: 2026-02-02 | Vibe Check: Enterprise Choice - Better than GitHub for large organizations with complex workflows. Strong Azure integration. Boards more powerful than GitHub Projects. Free tier generous. UI less polished than GitHub.
Tags: azure-devops, devops, ci-cd, microsoft, pipelines