Build a CI/CD Pipeline with Azure DevOps

Build a multi-stage YAML pipeline that deploys a Node.js app automatically.

Introduction

30 Second Summary

Every time a developer finishes writing code, someone has to build it, test it, and get it running on a live server. Without automation, that process is slow, error-prone, and honestly kind of painful.

In this project, you will build a CI/CD pipeline in Azure DevOps that automatically builds, tests, and deploys a Node.js web app to a live URL every time you push code.

What You'll Build

A complete multi-stage YAML pipeline that takes a Node.js Express app from code push to live deployment on Azure App Service, fully automated.

By the end of this project, you'll have:

  • An Azure DevOps organization, project, and Azure Repos repository hosting a Node.js app with unit tests.
  • A multi-stage YAML pipeline that automatically builds, tests, and deploys your app whenever code is pushed.
  • A service connection linking Azure DevOps to your Azure subscription, enabling automated cloud deployments.
  • A live web app running on Azure App Service's free tier, plus a manual approval gate and pipeline status badge as a secret mission.

Are there any prerequisites?

You'll need an Azure account (free or pay-as-you-go) and basic familiarity with Git commands like clone, commit, and push. No credit card is required for Azure DevOps itself. You'll install Node.js and Git in the first step if you don't have them already.

Set Up Azure DevOps and Your Local Environment

Before you can build a pipeline, you need the tools and platform to run it on. In this step, you'll install Node.js and Git on your machine, create an Azure DevOps organization with a project, and clone the repository so you're ready to start writing code.

In This Step, Get Ready To:
  • Install Node.js, npm, and Git on your local machine.
  • Create an Azure DevOps organization and project with a Git repository.
  • Clone the Azure Repos repository to your local machine.
Install Node.js and Git

Your CI/CD pipeline will build and test a Node.js app, so you need Node.js and its package manager npm installed locally. You also need Git to push code to your Azure Repos repository.

  • Download and install Node.js LTS from https://nodejs.org. This includes npm automatically.
  • Download and install Git from https://git-scm.com if you don't already have it.
  • Open a terminal and verify your installations by running the following commands:
node --version
npm --version
git --version

I see version numbers

You're all set. Each command should print a version number like v20.x.x, 10.x.x, and 2.x.x respectively.

Command not found

If you see "command not found" for any of these, the installation didn't complete or your terminal can't find the program.

  • Close and reopen your terminal. Some installations require a fresh session to update your PATH.
  • Re-run the installer and make sure to check any option that says "Add to PATH".
  • On Windows, try running the commands in a new PowerShell window instead of Command Prompt.

Still stuck? Ask for help troubleshooting your Node.js or Git installation.

Create an Azure DevOps Organization and Project

Azure DevOps is the platform where your pipeline will live. An organization is the top-level container, and a project inside it holds your repository, pipelines, and settings.

  • Navigate to https://dev.azure.com and sign in with your Microsoft account.
  • Create a new organization if you don't already have one.
  • Click New project in the top right corner.
  • Enter nodejs-cicd-pipeline as the project name.
  • Select Git for version control. You can leave the visibility as private.
  • Click Create.

What is Azure DevOps?

Azure DevOps is a suite of developer services for planning, building, testing, and deploying software. It includes Azure Repos (Git repositories), Azure Pipelines (CI/CD), Azure Boards (work tracking), and more. The free tier includes up to 5 Basic users, unlimited private Git repos, and 1,800 minutes per month of Microsoft-hosted pipeline time.

Now you need to verify that your organization has access to Microsoft-hosted parallel jobs. Without this, your pipeline won't be able to run.

  • Click Organization settings at the bottom left of the Azure DevOps page.
  • Select Pipelines, then Parallel jobs.
  • Confirm that the Microsoft-hosted section shows at least 1 parallel job.

No parallel jobs? You may need to request access

New Azure DevOps organizations may not automatically receive the free Microsoft-hosted parallel job grant. If you see 0 parallel jobs, submit a request at https://aka.ms/azpipelines-parallelism-request.

Approval can take a few business days. You can continue setting up your project and code in the meantime, but your pipeline won't run until the grant is approved.

Clone the Azure Repos Repository Locally

Your new project comes with an empty Git repository in Azure Repos. You need to clone this repository to your local machine so you can add code and push it back.

  • In your Azure DevOps project, click Repos in the left sidebar.
  • Click the Clone button in the top right and copy the HTTPS clone URL.
  • Open a terminal and run the following command:
git clone [[REPO_URL="your Azure Repos HTTPS clone URL"]]
  • When prompted for credentials, follow the Azure DevOps instructions to generate a Git credential or use a personal access token.
  • Navigate into the cloned directory:
cd nodejs-cicd-pipeline

What is Azure Repos?

Azure Repos is the Git hosting service inside Azure DevOps. It works just like GitHub or GitLab. Your pipeline will watch this repository for new pushes and trigger automatically.

Why Azure Repos instead of GitHub?

Azure DevOps pipelines work great with GitHub, but using Azure Repos keeps everything in one platform. Your repository, pipeline, service connections, and deployment environments all live under the same project. This gives you a more cohesive experience and avoids the cross-platform setup that GitHub integration requires.

Having trouble cloning?

If you see an authentication error, make sure you're using the HTTPS URL (not SSH). Azure DevOps may prompt you to create a password or personal access token for Git operations. Follow the on-screen prompts carefully.

Still stuck? Ask for help with Azure Repos authentication.

Your local environment is ready and connected to Azure DevOps. Next up, you'll create the Node.js app and push it to your repository.

Create the Node.js App with Unit Tests

Your Azure DevOps project has a repository, but it's empty. Before you can build a pipeline, you need something to build. In this step, you'll create a simple Node.js web app with unit tests, verify everything works locally, and push it to Azure Repos.

In This Step, Get Ready To:
  • Initialize a Node.js project and install Express and Jest.
  • Create the app and test files for your web server.
  • Run tests locally and push your code to Azure Repos.
Initialize the Node.js Project and Install Dependencies

Every Node.js project starts with a package.json file that tracks your project's dependencies and scripts. You'll also install two packages: Express for building the web server, and Jest for running unit tests.

  • Open your terminal and make sure you're inside the cloned repo directory from Step 1.
  • Run the following command to create a package.json with default settings:
npm init -y
  • Install Express as a production dependency:
npm install express
  • Install Jest as a development dependency:
npm install --save-dev jest

Why --save-dev?

The --save-dev flag tells npm that Jest is only needed during development and testing. It won't be included when your app is deployed to production. This keeps your deployed app lightweight.

Create the App and Test Files

You need three things: the Express app itself, a way to export it for testing, and a test file that verifies the app works. You'll split the app into two files so that Jest can test the Express routes without actually starting the server.

  • Create a file called app.js in the root of your project with the following content:
const express = require('express');
const app = express();

// Define the root route
app.get('/', (req, res) => {
  res.send('Welcome to my Azure DevOps CI/CD app!');
});

// Export the app for testing
module.exports = app;

Why export the app separately?

By exporting the Express app without calling app.listen() in this file, you keep the app definition separate from the server startup. This lets Jest import and test the routes without starting a real server on a port.

  • Create a file called server.js that starts the server:
const app = require('./app');

// Use the PORT environment variable provided by Azure App Service,
// or default to 3000 for local development
const port = process.env.PORT || 3000;

app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

Why process.env.PORT?

Azure App Service automatically provides a PORT environment variable that tells your app which port to listen on. If your app ignores this and hardcodes a port, it won't work when deployed. The || 3000 fallback lets you run the app locally on port 3000 during development.

  • Now install the supertest library, which lets Jest make HTTP requests to your Express app without starting the server:
npm install --save-dev supertest
  • Create a file called app.test.js with a unit test for the root route:
const request = require('supertest');
const app = require('./app');

// Test that the root route returns a 200 status and the expected message
describe('GET /', () => {
  it('should return the welcome message', async () => {
    const response = await request(app).get('/');
    expect(response.status).toBe(200);
    expect(response.text).toBe('Welcome to my Azure DevOps CI/CD app!');
  });
});

What does this test do?

This test uses supertest to send a GET request to the / route of your app. It then checks two things: that the HTTP status code is 200 (success) and that the response body matches your welcome message. Your CI/CD pipeline will run this test automatically on every push.

  • Open package.json and update the scripts section to match the following:
"scripts": {
  "test": "jest",
  "start": "node server.js"
}

Pro tip: only update the scripts section

Don't replace the entire package.json file. Just find the existing "scripts" block and replace it with the two lines above. The rest of the file (name, version, dependencies) should stay as-is.

Test Locally and Push to Azure Repos

Before pushing anything to your repository, you should always verify that your code works locally. This is exactly what your pipeline will do later, so catching issues now saves debugging time.

  • Run your unit tests:
npm test

I see tests passing

You should see output showing 1 test suite with 1 passing test. Something like:

PASS  ./app.test.js
  GET /
    ✓ should return the welcome message

Tests:       1 passed, 1 total

Your test is passing. Move on to testing the server.

I see an error

Common issues to check:

  • Make sure the welcome message string in app.test.js matches exactly what's in app.js.
  • Verify that app.js exports the app with module.exports = app;.
  • Confirm you installed both jest and supertest by checking your package.json devDependencies.

If you're still stuck, help me debug my failing Jest test.

  • Start the server to verify it works in your browser:
npm start
  • Open your browser and navigate to http://localhost:3000.

You should see your welcome message displayed in the browser. This confirms your Express app is working correctly.

  • Stop the server by pressing Ctrl+C in your terminal.

Now it's time to push your code to Azure Repos so your pipeline can access it.

  • Stage, commit, and push all your files:
git add .
git commit -m "Initial Node.js app with tests"
git push origin main

What does this command do?

These three Git commands work together. git add . stages all new and changed files. git commit saves a snapshot of those changes with a message. git push uploads the commit to your Azure Repos remote repository.

  • Go back to your Azure DevOps project in your browser.
  • Click Repos in the left sidebar.

You should see your files (app.js, server.js, app.test.js, package.json, and the node_modules folder) listed in your repository.

Pro tip: add a .gitignore

You may notice that the node_modules folder was pushed to your repo. In a real project, you'd create a .gitignore file containing node_modules/ to exclude it. The pipeline will run npm install on its own, so it doesn't need those files in the repo. For this project, it won't cause any issues either way.

Your app is built, tested, and living in Azure Repos. Next up, you'll create the Azure App Service that will host your app on the internet.

Create the Azure App Service for Deployment

Your Node.js app is built, tested, and living in Azure Repos. But a pipeline that only builds and tests is only half the story. You need somewhere for the pipeline to deploy to. In this step, you'll create an Azure App Service to host your web app, and then create a service connection so Azure DevOps has permission to deploy to it.

In This Step, Get Ready To:
  • Create an Azure App Service web app on the free F1 tier.
  • Create a service connection linking Azure DevOps to your Azure subscription.
Create the App Service in the Azure Portal

Azure App Service is a managed hosting platform for web apps. The free F1 tier gives you shared compute with 60 CPU minutes per day, 1 GB of RAM, and 1 GB of storage at no cost. That is more than enough for this project.

  • Go to https://portal.azure.com and sign in with your Azure account.
  • In the search bar at the top, type App Services and select it from the results.
  • Click **Create**, then select **Web App**.

You'll land on the web app creation form. Fill in the following details:

  • Select your Azure subscription from the **Subscription** dropdown.
  • Under **Resource Group**, click **Create new** and enter rg-nodejs-cicd.
  • Enter a globally unique **Name** for your web app (e.g., myapp-cicd-demo-12345). This name must be unique across all of Azure and can only contain letters, numbers, and hyphens.
  • Set **Publish** to **Code**.
  • Set **Runtime stack** to **Node 24 LTS**.
  • Set **Operating System** to **Linux**.
  • Select a **Region** close to you.

Why does the name need to be globally unique?

Your app name becomes part of the public URL: https://<your-app-name>.azurewebsites.net. Since this URL is accessible on the internet, no two App Service apps can share the same name. Adding a few random numbers to the end (like 12345) is an easy way to make it unique.

  • Under **Pricing plan**, click **Explore pricing plans** and select **Free F1**.
  • Click **Review + create** at the bottom of the page.
  • Review your settings, then click **Create**.

Azure will take a minute or two to provision your App Service. Once the deployment completes, you'll see a **Go to resource** button.

What should I see?

The App Service overview page shows your app's URL, status, and resource group. If you click the URL now, you'll see a default Azure placeholder page. That is expected. Your Node.js app will replace it once the pipeline deploys it.

Create the Service Connection in Azure DevOps

Your App Service exists, but Azure DevOps has no idea it's there. A service connection is a secure link between Azure DevOps and your Azure subscription. It gives your pipeline permission to deploy code to your App Service without you manually logging in each time.

  • Go back to your Azure DevOps project at https://dev.azure.com.
  • Click **Project settings** (gear icon) in the bottom-left corner.
  • Under **Pipelines**, click **Service connections**.
  • Click **New service connection**.
  • Select **Azure Resource Manager**, then click **Next**.
  • Select **App registration (automatic)** as the identity type.
  • Select **Workload identity federation** as the credential type.

What is Workload Identity Federation?

Workload identity federation lets Azure DevOps authenticate to Azure without storing any secrets. Instead of a password or certificate that could expire or leak, it uses a trust relationship between Azure DevOps and your Microsoft Entra tenant. This is the recommended approach for new service connections.

  • Select your **Azure subscription** from the dropdown.
  • Select the resource group you created earlier (rg-nodejs-cicd).
  • Enter a name for the service connection, such as azure-app-service-connection.
  • Check the box for **Grant access permission to all pipelines**.
  • Click **Save**.

Azure DevOps will automatically create an app registration in your Microsoft Entra tenant and assign it Contributor access to your resource group. This all happens behind the scenes in a few seconds.

Getting a permissions error?

The automatic app registration requires you to have the Owner role on your Azure subscription. If you see an error about insufficient permissions, you may need to ask your subscription owner to create the service connection for you, or use the manual approach instead. Help me troubleshoot my service connection error.

What should I see?

Your new service connection should appear in the Service connections list with a green checkmark. You'll see the connection name, the subscription it's linked to, and the resource group it has access to.

Your deployment target is ready and your pipeline has permission to reach it. Next up, you'll write the YAML pipeline that ties everything together: building, testing, and deploying your app automatically.

Build the Multi-Stage YAML Pipeline

Your App Service is live and your service connection is ready. Now it's time to tie everything together with the star of the show: the YAML pipeline. This single file will tell Azure DevOps exactly how to build, test, and deploy your app every time you push code.

Microsoft recommends YAML pipelines for all new projects because they live alongside your code in version control. That means your pipeline definition is tracked, versioned, and reviewable just like any other file in your repo.

In This Step, Get Ready To:
  • Write a multi-stage azure-pipelines.yml file with Build and Deploy stages.
  • Push the pipeline file and trigger your first automated pipeline run.
  • Verify your app is live at your Azure App Service URL.
Create the azure-pipelines.yml File

A multi-stage pipeline breaks your CI/CD process into distinct phases. Your pipeline will have two stages: a Build stage that installs dependencies and runs tests, and a Deploy stage that pushes your app to Azure App Service. The Deploy stage only runs if Build succeeds, so broken code never reaches production.

  • Open your cloned repo folder in your text editor.
  • Create a new file named azure-pipelines.yml at the root of the repository.
  • Paste the following YAML into the file:
trigger:
  - main

stages:
  # Build Stage: install dependencies and run tests
  - stage: Build
    displayName: 'Build and Test'
    jobs:
      - job: BuildJob
        pool:
          vmImage: 'ubuntu-latest'
        steps:
          - task: NodeTool@0
            inputs:
              versionSpec: '24.x'
            displayName: 'Install Node.js'

          - script: npm install
            displayName: 'Install dependencies'

          - script: npm test
            displayName: 'Run unit tests'

  # Deploy Stage: push the app to Azure App Service
  - stage: Deploy
    displayName: 'Deploy to Azure'
    dependsOn: Build
    condition: succeeded()
    jobs:
      - job: DeployJob
        pool:
          vmImage: 'ubuntu-latest'
        steps:
          - task: NodeTool@0
            inputs:
              versionSpec: '24.x'
            displayName: 'Install Node.js'

          - script: npm install --production
            displayName: 'Install production dependencies'

          - task: AzureWebApp@1
            inputs:
              azureSubscription: '[[SERVICECONNECTION="your-service-connection-name"]]'
              appName: '[[APPNAME="your-app-service-name"]]'
              package: '$(System.DefaultWorkingDirectory)'
            displayName: 'Deploy to App Service'

What does this pipeline do?

Here is a breakdown of the key sections:

  • trigger: - main tells Azure DevOps to run this pipeline automatically whenever code is pushed to the main branch.
  • The Build stage uses a Microsoft-hosted ubuntu-latest agent to install Node.js, run npm install, and execute your tests.
  • The Deploy stage uses dependsOn: Build and condition: succeeded() to ensure it only runs when the Build stage passes.
  • AzureWebApp@1 is the recommended task for deploying to Azure App Service. It uses your service connection to authenticate with Azure.
  • Replace the azureSubscription value with the exact name of the service connection you created in the previous step (e.g., azure-app-service-connection).
  • Replace the appName value with your App Service's name (e.g., myapp-cicd-demo-12345).
  • Save the file.

Pro tip: match names exactly

The azureSubscription value must match your service connection name character for character. If you named it azure-app-service-connection, do not write Azure-App-Service-Connection. You can double-check the name in Project settings > Service connections.

Why YAML over Classic pipelines?

Azure DevOps also offers a visual "Classic" pipeline editor, but Microsoft recommends YAML pipelines for all new projects. YAML pipelines are versioned alongside your code, so you get full traceability and branch-specific customization. Classic pipelines are maintained for backwards compatibility but are not the recommended path forward.

Commit and Push the Pipeline File

With the YAML file saved, you need to push it to Azure Repos so Azure DevOps can detect it. Then you will create the pipeline in the Azure DevOps web portal.

  • Open your terminal in the repo directory.
  • Run the following commands to stage, commit, and push:
git add azure-pipelines.yml
git commit -m "Add CI/CD pipeline"
git push origin main

Now create the pipeline in Azure DevOps so it knows to use this file.

  • In the Azure DevOps web portal, go to Pipelines in the left sidebar.
  • Click New pipeline.
  • Select Azure Repos Git as the code source.
  • Select your repository.

Azure DevOps detects the existing azure-pipelines.yml file in your repo and shows you a preview of its contents.

  • Review the YAML preview to make sure it matches what you wrote.
  • Click Run to trigger your first pipeline run.
Watch the Pipeline Run and Verify Deployment

This is the moment where everything comes together. You can watch each stage execute in real time from the Azure DevOps web UI.

  • Click on the running pipeline to see the stage view.
  • Watch the Build and Test stage complete. You can click into the job to see logs for each step (Node.js install, npm install, tests).

What should I see?

The pipeline view shows your two stages as connected boxes. The Build stage runs first, and once it shows a green checkmark, the Deploy stage begins automatically. Each stage expands to show individual task logs.

Pipeline is running smoothly

If both stages show green checkmarks, your pipeline ran successfully. Move on to verify the deployment.

Pipeline asks to permit access

The first time your pipeline uses a service connection, Azure DevOps may pause and ask you to permit access. This is a security feature.

  • Click View on the permission prompt.
  • Click Permit to allow the pipeline to use your service connection.

The pipeline resumes automatically after you grant permission.

I see an error

Click into the failed stage and expand the task that has a red X to read the error log. Common issues include:

  • Service connection name mismatch. Verify the azureSubscription value in your YAML matches your service connection name exactly.
  • App name mismatch. Verify the appName value matches your App Service name in the Azure Portal.
  • Test failures. Check the npm test output. Your tests must pass for the Deploy stage to run.

If you are stuck, help me debug my pipeline error.

Once both stages show green checkmarks, your app is live.

  • Open your browser and navigate to https://your-app-name.azurewebsites.net.

You should see the welcome message from your Express app. This page was deployed automatically by your pipeline.

Your CI/CD pipeline is fully operational. Next up, you will trigger it with a real code change to experience the complete automation loop.

Trigger the Pipeline with a Code Change

You have a working pipeline that builds, tests, and deploys your app. But the real power of CI/CD is that it runs automatically every time you push code. In this step, you will make a code change, push it, and watch the entire pipeline fire without you lifting a finger.

In This Step, Get Ready To:
  • Update your app's welcome message and push the change to Azure Repos.
  • Watch the pipeline trigger automatically and run through both stages.
  • Verify the updated app is live on Azure App Service.
Make a Code Change and Push

Your azure-pipelines.yml file has a trigger set on the main branch. Any push to main will kick off the pipeline. Let's test that by changing the welcome message in your app.

  • Open app.js in your text editor.
  • Find the welcome message string in your root route (e.g., "Welcome to my app") and change it to something new, like "Hello from Azure DevOps CI/CD!".
  • Save the file.

Now stage, commit, and push the change.

git add app.js
git commit -m "Update welcome message"
git push origin main

What does this command do?

These three commands stage your changed file, create a commit with a descriptive message, and push it to the main branch in Azure Repos. The push is what triggers your pipeline.

Watch the Automated Pipeline

The moment your push lands in Azure Repos, your pipeline's trigger fires. You can watch the entire process unfold in real time.

  • Go to Pipelines in the left sidebar of your Azure DevOps project.
  • Click on the new pipeline run that appeared. It should show your commit message "Update welcome message".
  • Click into the Build stage to watch it install dependencies and run your tests.
  • Once the Build stage succeeds, watch the Deploy stage push your updated code to Azure App Service.

What should I see?

You should see both stages light up green with checkmarks. The Build stage runs npm install and npm test, and the Deploy stage uses the AzureWebApp@1 task to push your code to your App Service. The whole run typically takes 1-3 minutes.

Pipeline Not Triggering?

If you don't see a new pipeline run, double-check that your azure-pipelines.yml trigger is set to the main branch and that you pushed to main (not a different branch). Also confirm your pipeline is enabled under Pipelines. Help me troubleshoot my pipeline trigger.

Verify the Live Update

The final proof that your CI/CD pipeline works end-to-end is seeing the updated message live on the internet.

  • Open your browser and navigate to https://your-app-name.azurewebsites.net.
  • Confirm that your updated welcome message is now displayed.

You just experienced the full CI/CD loop. You changed one line of code, pushed it, and your pipeline automatically built the app, ran the tests, and deployed the update to a live URL. Zero manual steps.

Why Is This a Big Deal?

Without CI/CD, deploying a code change means manually building, testing, and uploading your app every single time. With the pipeline you just built, every push to main triggers the same reliable, automated process. This is exactly how professional development teams ship code multiple times a day.

Your pipeline is fully operational. Next up, take on the Secret Mission to add a manual approval gate before deployments and a status badge to your README.

Secret mission

Add an Approval Gate and Pipeline Badge

In production environments, teams never deploy straight to live without someone signing off first. In this secret mission, you'll add a manual approval gate before the Deploy stage and a pipeline status badge to your README so your repo shows build health at a glance.

Before you go

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses Azure App Service on the Free F1 tier and Azure DevOps on the free tier, so there are no ongoing costs for keeping everything running.

Resources you used:

  • Azure App Service web app (Free F1 tier, no cost).
  • Azure resource group containing the App Service and its plan.
  • Azure DevOps organization, project, and Azure Repos repository (free for up to 5 Basic users).
  • Azure Resource Manager service connection with workload identity federation.
  • Local Node.js project files on your computer.

Keep everything running

No action needed. Choose this if you are still actively building or want to keep experimenting with your pipeline.

  • Your Azure App Service runs on the Free F1 tier, which is always free. It will not incur any charges.
  • Your Azure DevOps organization is free for up to 5 Basic users with 1,800 minutes per month of Microsoft-hosted pipeline time.
  • Your pipeline will continue to trigger automatically whenever you push code to the main branch.

Pause - I'll come back to this later

Since all resources are on free tiers, pausing is optional. However, you can stop the App Service to free up the shared compute allocation.

  • In the Azure Portal, navigate to your App Service.
  • Click Stop in the top toolbar to shut down the web app.
  • Your Azure DevOps project, repository, and pipeline configuration will remain intact.
  • When you are ready to resume, navigate back to the App Service and click Start.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow these steps to clean up everything.

  • In the Azure Portal, search for Resource groups and select your resource group (e.g., rg-nodejs-cicd).
  • Click Delete resource group, type the resource group name to confirm, and click Delete. This removes the App Service, the App Service plan, and all associated resources.
  • In Azure DevOps, go to Organization settings, then Projects. Select your project and click Delete.
  • If you no longer need the Azure DevOps organization, you can delete it from Organization settings as well.
  • Delete the local project folder from your computer.

Mission accomplished

That's a Wrap!

Nice work! You just built a professional-grade CI/CD pipeline from scratch using Azure DevOps. Every time you push code, your pipeline automatically builds, tests, and deploys your app to a live URL. That is the exact workflow used by real development teams in production.

Here's what you learned:

  • Set up an Azure DevOps organization with a project, repository, and a Node.js Express app with unit tests.
  • Wrote a multi-stage YAML pipeline with Build and Deploy stages, connected to Azure App Service through a service connection using workload identity federation.
  • Experienced the full CI/CD loop: pushed a code change and watched it automatically build, test, and deploy to a live Azure App Service URL with zero manual steps.
  • Added a manual approval gate before the Deploy stage using environment-based approvals, and added a pipeline status badge to your repo's README.

Ready to quiz yourself?