Release apps with Azure Pipelines

Learn to release apps with Azure Pipelines in this hands-on Azure tutorial. Master pipelines for continuous delivery, automate releases, troubleshoot common issues, and discover what to study next.

Focus: release apps with azure pipelines

Sponsored

You've built a solid CI pipeline that compiles code and runs tests on every push — but your users are still waiting weeks for a manual deployment. The gap between a green build and a live update is where releases stall, and teams resort to copy-pasting artifacts and praying they remembered every environment variable. In this lesson, you'll close that gap by using Azure Pipelines to release apps automatically — turning a finished build into a production deployment with repeatable, auditable steps.

The problem this lesson solves

Manual releases are slow, error-prone, and opaque. A single forgotten configuration value or a slightly different runtime environment can turn a 'known good' build into an outage. When you release apps with Azure Pipelines, you replace those copy-paste rituals with a defined, automated process that runs the same way every time.

The pain is real: 60% of deployment failures trace back to manual steps or environment drift. Every time a human is in the loop, you introduce risk — typos, skipped steps, or 'it works on my machine' assumptions. Azure Pipelines gives you a release pipeline that deploys your artifact to any target — virtual machines, containers, Kubernetes, or app services — with gates, approvals, and rollback strategies built in.

By the end of this lesson, you'll be able to automate a release from a build artifact to a live environment, and you'll know exactly when to use a multi-stage YAML pipeline versus a classic release definition.

Core concept / mental model

Think of a release pipeline as a conveyor belt that carries your build artifact from the packaging station (CI) to the loading dock (production). Each stage — Dev, Test, Staging, Prod — is a stop on that belt where you inspect, approve, and sign off before the artifact moves on.

Azure Pipelines offers two complementary models:

  • Classic release pipelines: A visual designer where you define stages, approvals, and gates in the Azure DevOps UI. Great for quick setups or when you want to avoid YAML.
  • Multi-stage YAML pipelines: The same YAML file that defines your build and release, enabling pipeline-as-code. Everything lives in your repo, versioned and reviewable.

Pro tip: Think of the 'release' as everything that happens after the build artifact is ready. CI answers 'does it compile and pass tests?' Release answers 'is it safe to put in front of users?' — a different question with different answers.

Key vocabulary:

  • Artifact: The packaged output of your build (e.g., a .zip, a Docker image, a .jar). This is the thing your release pipeline consumes.
  • Stage: A logical environment in your release (Dev, QA, Prod). Stages run sequentially by default and can have approvals.
  • Approval: A manual check before a stage runs — a human gate that says 'yes, deploy here.'
  • Gate: An automated check that polls a service (e.g., a monitoring endpoint) before allowing the release to continue.

How it works step by step

  1. Build completes and publishes an artifact — your CI pipeline produces a package and uploads it as a pipeline artifact.
  2. Release pipeline triggers — automatically when a new build artifact is available, or manually.
  3. Stages execute in order — Dev deploys, runs smoke tests; if that passes, Test deploys with automated integration tests; then Staging and Prod follow.
  4. Approvals gate the production stage — a human (or automated gate) reviews the test results and gives the green light.
  5. Deployment happens — the pipeline runs your deployment scripts or uses a built-in task (like AzureWebApp or KubernetesManifest) to push the artifact.
  6. Post-deployment validation — health checks or monitoring confirm the app is live and healthy.

Each step is a cause → effect chain: a failed test in stage 2 stops the belt, so bad code never reaches production. This is the power of continuous delivery (CD) — you're always one approval away from shipping.

Hands-on walkthrough

Let's build a release pipeline from scratch. We'll use a multi-stage YAML pipeline because it's versionable and the modern default. The example deploys a simple web app to an Azure App Service, but the pattern applies to any target.

1. Structure your repository

Assume your azure-pipelines.yml contains a CI stage that builds and publishes an artifact. Here's a minimal CI setup that produces a deployable zip:

# azure-pipelines.yml (root)
trigger:
  branches:
    include:
      - main

stages:
- stage: Build
  jobs:
  - job: BuildJob
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - script: |
        echo "Building the app..."
        # Your actual build commands here
        mkdir -p output
        echo 'Hello from release!' > output/index.html
      displayName: 'Build and package'
    - publish: output
      artifact: webapp

2. Add release stages

Extend that same file with a deployment job that pushes the artifact to a pre-configured App Service. The deployment keyword creates an environment where approvals and gates live.

stages:
- stage: Build
  jobs:
  - job: BuildJob
    steps:
      # ... build steps from above ...

- stage: DeployToDev
  dependsOn: Build
  jobs:
  - deployment: DeployWebApp
    environment: 'dev'
    strategy:
      runOnce:
        deploy:
          steps:
          - download: current
            artifact: webapp
          - task: AzureWebApp@1
            inputs:
              azureSubscription: '<your-service-connection>'
              appName: 'myapp-dev'
              package: '$(Pipeline.Workspace)/webapp/**/*.zip'

Add a production stage with an approval. To require a human gate, navigate to Pipelines → Environments → prod → Approvals and checks, and add an approval. The YAML references that environment:

- stage: DeployToProd
  dependsOn: DeployToDev
  jobs:
  - deployment: DeployWebAppToProd
    environment: 'prod'
    strategy:
      runOnce:
        deploy:
          steps:
          - download: current
            artifact: webapp
          - task: AzureWebApp@1
            inputs:
              azureSubscription: '<your-service-connection>'
              appName: 'myapp-prod'
              package: '$(Pipeline.Workspace)/webapp/**/*.zip'

When you push this file, the pipeline runs the Build stage, deploys to Dev automatically, then pauses at Prod until you approve it. That's release apps with Azure Pipelines in action.

Expected output in the Azure DevOps UI: the Build stage shows green, DeployToDev runs and completes, then DeployToProd shows 'Waiting for approval'. Approve it, and the prod deployment executes.

3. Classic release pipeline (alternative)

If you prefer point-and-click, create a Release Pipeline in the Releases tab. Add an artifact source (your build pipeline), define stages (Dev, Prod), and add deployment tasks like Azure App Service deploy. The workflow is identical, just managed through the UI instead of YAML.

Compare options / when to choose what

Option Best for Pros Cons
Multi-stage YAML Teams that treat CI/CD as code Versionable, reviewable, reuses build YAML, natively tracks environments Requires YAML knowledge; approvals are configured in the UI (not fully in YAML)
Classic release pipeline Quick setups, non-developers Visual drag-and-drop, familiar UI, approvals are part of the definition Harder to version, drift between environments, separate from build YAML
Azure DevOps Starter / built-in templates Simple apps or demos Fastest setup Limited customization, not suitable for complex release logic

When to choose what: Start with multi-stage YAML for any real project. It forces you to define releases as code, which pays off in auditability and reproducibility. Use classic only when you need a one-off or your team isn't comfortable with YAML yet.

Troubleshooting & edge cases

  • "No agent found" for deployment jobs: Your self-hosted agent may lack required software (e.g., Docker, .NET). Ensure the agent pool has the necessary runtimes for your deployment tasks.
  • Approval never completes: Approvals are assigned to specific users or groups. If the approver doesn't have permissions on the environment, the pipeline waits forever. Check the environment security settings.
  • Artifact not found: The download: current step fails if the artifact name doesn't match. Verify the publish name in the build stage.
  • AzureWebApp task fails with 'Package not found': Your package path is wrong. Use $(Pipeline.Workspace)/**!(*.zip) or the exact zip name—test the path in a debug step.
  • Multiple apps, one service connection: Four different App Services each need a separate appName; don't reuse one stage for all.
  • YAML stages running in parallel: If you forgot dependsOn, stages may run concurrently. Set explicit dependsOn to keep the order.
  • Security: Your service connection credentials are stored in Azure DevOps — don't hardcode passwords; use variables and secret variable groups.

What you learned & what's next

You now understand how to release apps with Azure Pipelines: from creating a multi-stage pipeline, to deploying an artifact to Dev and Production with approvals, to troubleshooting common failures. You've met both learning objectives — you can explain the core idea (automated, gated deployments from build artifacts) and complete a practical exercise (the YAML walkthrough above).

Next in the Azure tutorial path, you'll explore how to monitor and observe those deployed apps—turning telemetry into proactive alerts, so you're not just releasing fast but also confidently. Keep your pipeline green, and the next lesson will keep it healthy.

Practice recap

Extend the example pipeline: add a Test stage that runs a simple integration test (e.g., curl the dev web app) before deploying to production. Then configure an approval on the prod environment and run the pipeline. Observe the behavior when the test fails — does the release stop?

Common mistakes

  • Forgetting to publish the build artifact — the release pipeline has nothing to download, and the deployment fails with 'artifact not found'.
  • Skipping the dependsOn in YAML stages — stages run in parallel, so production can deploy before dev finishes.
  • Hardcoding secrets in the pipeline YAML — use secret variables or Azure Key Vault instead.
  • Approvals configured on the wrong environment — the pipeline waits forever if the approver isn't in the security group.

Variations

  1. Use a classic Release Pipeline in the Azure DevOps UI for a no-YAML approach.
  2. Deploy to Kubernetes using the KubernetesManifest task instead of App Service.
  3. Add automated gates (e.g., monitoring query) before the production stage instead of a manual approval.

Real-world use cases

  • Automate deployment of a web app to Azure App Service with separate Dev/Prod slots.
  • Roll out a containerized microservice to Azure Kubernetes Service using a multi-stage YAML pipeline.
  • Manage compliance by requiring manual approval before every production release for regulated industries.

Key takeaways

  • A release pipeline consumes build artifacts and deploys them through stages.
  • Multi-stage YAML is the modern, versionable approach; classic releases are the visual alternative.
  • Approvals and gates protect production environments from unverified changes.
  • Always publish an artifact in CI so the release can download it.
  • Set dependsOn explicitly to control stage order and avoid parallel mistakes.
  • Use service connections and secret variables to keep credentials safe.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.