How to Deploy a Node.js App to Azure App Service with CI/CD

Option A: Code-Based Deployment (Recommended for Most Users)

If you don’t need a custom runtime or container, Azure’s built-in code deployment option is the fastest and easiest way to host production-ready Node.js applications. Azure provides a managed environment with runtime support for Node.js, and you can automate everything using Azure DevOps.

This option is ideal for most production use cases that:

  • Use standard versions of Node.js (or Python, .NET, PHP)
  • Don’t require custom OS packages or NGINX proxies
  • Want quick setup and managed scaling

This section covers everything you need to deploy your Node.js app using Azure’s built-in runtime and set it up for CI/CD in Azure DevOps.

Step 0: Prerequisites and Permissions

Before starting, make sure you have the following:

  1. Azure Subscription with Contributor access
  2. Azure CLI installed and authenticated (az login)
  3. Azure DevOps Organization & Project
  4. Code repository in Azure Repos or GitHub (we’ll use Azure Repos)
  5. A user with the following roles:
    • Contributor on the Azure resource group
    • Project Administrator or Build Administrator in Azure DevOps (to create pipelines and service connections)

Step 1: Create an Azure Resource Group

az group create --name prod-rg --location eastus

Step 2: Choose Your Deployment Model

There are two main ways to deploy to Azure App Service:

  • Code-based: Azure manages the runtime (Node.js, Python, etc.)
  • Docker-based: You provide a custom Docker image

Option A: Code-Based App Service Plan

az appservice plan create \
  --name prod-app-plan \
  --resource-group prod-rg \
  --sku P1V2 \
  --is-linux
  • az appservice plan create: Command to create a new App Service Plan (defines compute resources)
  • --name prod-app-plan: The name of the service plan to create
  • --resource-group prod-rg: The name of the resource group where the plan will reside
  • --sku P1V2: The pricing tier (Premium V2, small instance). Includes autoscaling, staging slots, etc.
  • --is-linux: Specifies the operating system for the app as Linux (required for Node.js apps)

Create Web App with Built-In Node Runtime

az webapp create \
  --name my-prod-node-app \
  --resource-group prod-rg \
  --plan prod-app-plan \
  --runtime "NODE|18-lts"
  • az webapp create: Creates the actual web app that will host your code
  • --name my-prod-node-app: The globally unique name of your app (will be part of the public URL)
  • --resource-group prod-rg: Assigns the app to the specified resource group
  • --plan prod-app-plan: Binds the app to the previously created compute plan
  • --runtime "NODE|18-lts": Specifies the Node.js runtime version (Node 18, LTS channel)

Option B: Docker-Based App Service Plan

az appservice plan create \
  --name prod-docker-plan \
  --resource-group prod-rg \
  --sku P1V2 \
  --is-linux
  • Same as Option A — this creates a Linux-based Premium plan
  • You can reuse this compute plan for one or more container-based apps

Create Web App Using Custom Docker Image

az webapp create \
  --name my-docker-app \
  --resource-group prod-rg \
  --plan prod-docker-plan \
  --deployment-container-image-name myregistry.azurecr.io/myapp:latest
  • --name my-docker-app: A unique name for your app
  • --resource-group prod-rg: Associates this web app with your resource group
  • --plan prod-docker-plan: Assigns the app to your App Service Plan
  • --deployment-container-image-name: Specifies the full path to your Docker image (from ACR or Docker Hub)

Use this if you’re building a containerized app and want full control of the runtime environment. Make sure your image is accessible in Azure Container Registry or Docker Hub.

Step 3: Prepare Your Azure DevOps Project

  1. Navigate to https://dev.azure.com
  2. Create a new Project (e.g., ProdWebApp)
  3. Go to Repos and push your Node.js code:
git remote add origin https://dev.azure.com/<org>/<project>/_git/my-prod-node-app
git push -u origin main

Step 4: Create a Service Connection

  1. In DevOps, go to Project Settings > Service connections
  2. Click New service connection > Azure Resource Manager
  3. Choose Service principal (automatic)
  4. Select the correct subscription and resource group
  5. Name it something like AzureProdConnection

Step 5: Create the CI/CD Pipeline

Add the following to your repository root as .azure-pipelines.yml.

Code-Based YAML Example

trigger:
  branches:
    include:
      - main

pool:
  vmImage: 'ubuntu-latest'

stages:
- stage: Build
  jobs:
  - job: BuildApp
    steps:
    - task: NodeTool@0
      inputs:
        versionSpec: '18.x'

    - script: |
        npm install
        npm run build
      displayName: 'Install and Build'

    - task: ArchiveFiles@2
      inputs:
        rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
        archiveFile: '$(Build.ArtifactStagingDirectory)/app.zip'
        includeRootFolder: false

    - task: PublishBuildArtifacts@1
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)'
        ArtifactName: 'drop'

- stage: Deploy
  dependsOn: Build
  jobs:
  - deployment: DeployWebApp
    environment: 'production'
    strategy:
      runOnce:
        deploy:
          steps:
          - task: AzureWebApp@1
            inputs:
              azureSubscription: 'AzureProdConnection'
              appName: 'my-prod-node-app'
              package: '$(Pipeline.Workspace)/drop/app.zip'

Docker-Based YAML Example

trigger:
  branches:
    include:
      - main

pool:
  vmImage: 'ubuntu-latest'

stages:
- stage: Deploy
  jobs:
  - deployment: DeployContainer
    environment: 'production'
    strategy:
      runOnce:
        deploy:
          steps:
          - task: AzureWebAppContainer@1
            inputs:
              azureSubscription: 'AzureProdConnection'
              appName: 'my-docker-app'
              containers: 'myregistry.azurecr.io/myapp:latest'

Step 6: Configure Pipeline and Approvals

  1. Go to Pipelines > Pipelines > New
  2. Select Azure Repos Git, choose your repo, and point to the YAML file
  3. Click Run Pipeline

To add manual approvals:

  1. Go to Pipelines > Environments
  2. Create a new environment named production
  3. Link the deploy stage to this environment in your YAML:
environment: 'production'
  1. Enable approval and checks for production safety

Step 7: Store Secrets (Optional but Recommended)

  1. Go to Pipelines > Library
  2. Create a new Variable Group (e.g., ProdSecrets)
  3. Add variables like DB_PASSWORD, API_KEY, and mark them as secret
  4. Reference them in pipeline YAML:
variables:
  - group: 'ProdSecrets'

Troubleshooting Tips

Problem Solution
Resource group not found Make sure you created it with az group create
Runtime version not supported Run az webapp list-runtimes --os linux to see current options
Pipeline can’t deploy Check if the service connection has Contributor role on the resource group
Build fails Make sure you have a valid package.json and build script

Summary

By the end of this process, you will have:

  • A production-grade Node.js app running on Azure App Service
  • A scalable App Service Plan using Linux and Premium V2 resources
  • A secure CI/CD pipeline that automatically builds and deploys from Azure Repos
  • Manual approval gates and secrets management for enhanced safety
  • The option to deploy using either Azure-managed runtimes or fully custom Docker containers

This setup is ideal for fast-moving

Leave a Reply

Your email address will not be published. Required fields are marked *

0