Building on our previous post about implementing dev-to-prod promotion with GitHub Actions, this follow-up demonstrates the same “build once, deploy everywhere” pattern using Azure DevOps Pipelines. You’ll learn how to leverage Azure DevOps YAML pipelines with Azure Developer CLI (azd). This approach ensures consistent, reliable deployments across environments.Environment-Specific InfrastructureThe infrastructure approach is identical to our previous GitHub Actions implementation. It uses conditional Bicep deployment with a single envType parameter. This drives environment-specific resource configuration. The same Bicep templates work seamlessly across both CI/CD platforms.For the complete infrastructure setup details, refer to the GitHub Actions post.From File Backup to Pipeline ArtifactsThe original approach used local file backups (copying zip files within the same job). However, the community pointed out that using native CI/CD artifact systems is more idiomatic. This provides several key advantages:Cross-job compatibility: Artifacts work seamlessly across multiple jobs and stages.Automatic cleanup: The platform handles retention policies automatically.Better traceability: Artifacts are visible in the platform UI with download history.Platform integration: Native features with built-in security and access controls.This artifact-based approach represents the industry standard for “build once, deploy everywhere” patterns. It works across modern CI/CD platforms. We have updated the original GitHub Actions implementation to use the same pattern demonstrated in this Azure DevOps version.Azure DevOps Pipeline EnhancementAzure DevOps pipelines require a different approach than GitHub Actions. However, they achieve the same outcome. We’ll demonstrate a multi-stage pipeline that provides proper separation of concerns and enterprise-ready deployment patterns. This staged approach offers better isolation, approval workflows, and traceability compared to single-job pipelines.The enhanced pipeline follows a three-stage structure:1. Pipeline StructureThe multi-stage pipeline uses separate stages for build, development deployment, and production promotion:# Run when commits are pushed to maintrigger: - mainpool: vmImage: ubuntu-lateststages:- stage: build_and_test- stage: deploy_development dependsOn: build_and_test- stage: promote_to_Prod dependsOn: deploy_development2. Build and Package StageThe first stage focuses solely on building and packaging the application for deployment:- stage: build_and_test jobs: - job: buildAndPackage pool: vmImage: ubuntu-latest steps: - task: Bash@3 displayName: Install azd inputs: targetType: 'inline' script: | curl -fsSL https://aka.ms/install-azd.sh | bash - task: PowerShell@2 displayName: Configure AZD to Use AZ CLI Authentication. inputs: targetType: inline script: | azd config set auth.useAzCliAuth "true" pwsh: true - task: AzureCLI@2 displayName: Package Application inputs: azureSubscription: azconnection scriptType: bash scriptLocation: inlineScript keepAzSessionActive: true inlineScript: | mkdir -p ./dist azd package app --output-path ./dist/app-package.zip --no-prompt echo "✅ Application packaged successfully" - task: PublishPipelineArtifact@1 displayName: Upload Package Artifact inputs: targetPath: './dist/app-package.zip' artifact: 'app-package' publishLocation: 'pipeline'3. Deploy to Development StageThe second stage provisions development infrastructure and deploys the packaged application:- stage: deploy_development dependsOn: build_and_test jobs: - job: deployToDevelopment pool: vmImage: ubuntu-latest steps: - task: Bash@3 displayName: Install azd inputs: targetType: 'inline' script: | curl -fsSL https://aka.ms/install-azd.sh | bash - task: PowerShell@2 displayName: Configure AZD to Use AZ CLI Authentication. inputs: targetType: inline script: | azd config set auth.useAzCliAuth "true" pwsh: true - task: AzureCLI@2 displayName: Provision DEV Infrastructure inputs: azureSubscription: azconnection scriptType: bash scriptLocation: inlineScript keepAzSessionActive: true inlineScript: | azd provision --no-prompt - task: DownloadPipelineArtifact@2 displayName: Download Package Artifact inputs: buildType: 'current' artifactName: 'app-package' targetPath: './artifacts' - task: AzureCLI@2 displayName: Deploy to Development inputs: azureSubscription: azconnection scriptType: bash scriptLocation: inlineScript keepAzSessionActive: true inlineScript: | azd deploy app --from-package ./artifacts/app-package.zip --no-prompt4. Validation GateAdd validation checks before promotion to production: - task: AzureCLI@2 displayName: Validate Application inputs: azureSubscription: azconnection scriptType: bash scriptLocation: inlineScript keepAzSessionActive: true inlineScript: | echo "🔍 Validating application in development environment..." # TODO: Add actual validation here # Examples: # - Health checks and integration tests # - Security and compliance scanning # - Performance validation sleep 3 # Simulate validation time echo "✅ Application validation passed"5. Promote to Production StageThe final stage uses environment-specific variables to deploy to production:- stage: promote_to_Prod dependsOn: deploy_development jobs: - job: deployProduction # use prod settings to override default environment variables # this variables become ENV VARS for all tasks in this job variables: AZURE_ENV_NAME: $(AZURE_PROD_ENV_NAME) AZURE_ENV_TYPE: $(AZURE_PROD_ENV_TYPE) AZURE_LOCATION: $(AZURE_PROD_LOCATION) AZURE_SUBSCRIPTION_ID: $(AZURE_PROD_SUBSCRIPTION_ID) pool: vmImage: ubuntu-latest steps: - task: Bash@3 displayName: Install azd inputs: targetType: 'inline' script: | curl -fsSL https://aka.ms/install-azd.sh | bash - task: PowerShell@2 displayName: Configure AZD to Use AZ CLI Authentication. inputs: targetType: inline script: | azd config set auth.useAzCliAuth "true" pwsh: true - task: DownloadPipelineArtifact@2 displayName: Download Package Artifact inputs: buildType: 'current' artifactName: 'app-package' targetPath: './artifacts' - task: AzureCLI@2 displayName: Deploy to PROD inputs: azureSubscription: azconnection scriptType: bash scriptLocation: inlineScript keepAzSessionActive: true inlineScript: | azd deploy app --from-package ./artifacts/app-package.zip --no-promptTry It OutYou can try this approach using the complete implementation hereWatch the walkthrough:PrerequisitesYou’ll need a Personal Access Token (PAT) to set up Azure DevOps pipelines with azd. For detailed guidance on PAT creation and pipeline setup, refer to the Microsoft Learn documentation.Setup Steps1. Initialize Projectazd init -t https://github.com/puicchan/azd-dev-prod-appservice-storageUse environment name like projazdo-dev.2. Edit azure.yamlMake sure you configure Azure DevOps as the CICD tool and add these pipeline variables:pipeline: provider: azdo variables: - AZURE_PROD_ENV_NAME - AZURE_PROD_ENV_TYPE - AZURE_PROD_LOCATION - AZURE_PROD_SUBSCRIPTION_ID3. Set Up Development Environmentazd up4. Set Up Production EnvironmentWe will run azd provision and rely on Azure Pipeline to deploy the app to production:azd env new projazdo-prodazd env set AZURE_ENV_TYPE prodazd provision5. Test the FlowSwitch back to Development:azd env select projazdo-devEdit your application code and make sure you run azd env set to configure the following environment variables the pipeline requires:AZURE_PROD_ENV_NAMEAZURE_PROD_ENV_TYPEAZURE_PROD_LOCATIONAZURE_PROD_SUBSCRIPTION_ID 6. Configure CI/CD Pipelineazd pipeline configGo to your Azure Pipelines Organization and check out the pipeline run.Pro Tip: Enhance Your Pipeline with AINeed help with Azure DevOps and azd? GitHub Copilot for Azure with Azure MCP can help you enhance your azure-dev.yml file directly in VS Code.With the GitHub Copilot for Azure extension installed, and the GitHub Copilot for Azure and Azure MCP tools enabled in Agent mode, GitHub Copilot can:Debug pipeline issues: Analyze YAML syntax errors and configuration problems.Add validation steps: Suggest health checks, security scans, or integration tests.Optimize deployment strategies: Recommend blue-green deployments or canary releases.Configure environment-specific logic: Help set up conditional steps for different environments.Simply ask GitHub Copilot questions like:“Add a health check validation step to my Azure DevOps pipeline”“How can I add manual approval gates before production deployment?”Agent mode with GitHub Copilot for Azure provides contextual understanding of your Azure resources. It can suggest pipeline improvements based on your specific infrastructure setup.ConclusionThis Azure DevOps implementation demonstrates how the “build once, deploy everywhere” pattern translates seamlessly across different CI/CD platforms. The core azd and Bicep logic remains identical. Meanwhile, platform-specific features like service connections and task definitions provide the Azure DevOps-native experience.Whether you choose GitHub Actions or Azure DevOps, the fundamental approach remains consistent. Conditional infrastructure deployment and package promotion ensure reliable deployments across your development lifecycle.Questions about implementation or want to share your Azure DevOps approach? Join the discussion here.The post Azure Developer CLI: From Dev to Prod with Azure DevOps Pipelines appeared first on Azure DevOps Blog.