Azure App Service is actually a distributed system that orchestrates multiple components to host your web application.

Here’s how a typical deployment from GitHub Actions to Azure App Service unfolds, showing the key components and their interactions:

Imagine you’ve just pushed a change to your GitHub repository.

  1. GitHub Actions Workflow Trigger: Your .github/workflows/deploy.yml file, residing in your repository, is triggered by the push event. This file contains the instructions for your deployment.

  2. Checkout Action: The actions/checkout@v3 action pulls your repository’s code into the ephemeral runner environment. This is the raw source code you’ll be deploying.

  3. Build Step: A build tool (like npm run build, mvn package, or dotnet publish) compiles your code, bundles assets, and prepares it for deployment. This might happen on the same runner or a separate build runner.

  4. Azure Login: The azure/login@v1 action authenticates your GitHub Actions runner with Azure using a Service Principal. This grants the runner the necessary permissions to interact with your Azure resources.

  5. Deployment to App Service: The azure/webapps-deploy@v2 action is the workhorse. It takes your built artifacts and deploys them to your Azure App Service instance. This is where the magic (and potential magic-breaking) happens.

Let’s see this in action with a sample workflow:

name: Deploy to Azure App Service

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v3

    - name: Set up Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18.x'

    - name: npm install and build
      run: |
        npm install
        npm run build

    - name: Azure Login
      uses: azure/login@v1
      with:

        creds: ${{ secrets.AZURE_CREDENTIALS }}


    - name: Deploy to Azure App Service
      uses: azure/webapps-deploy@v2
      with:
        app-name: 'my-awesome-app-service-name' # Replace with your App Service name
        package: 'dist' # Replace with your build output directory

In this workflow:

  • on: push: branches: - main means this workflow runs every time you push to the main branch.
  • runs-on: ubuntu-latest specifies the operating system for the runner.
  • The Set up Node.js step ensures you have the correct Node.js version.
  • npm install and npm run build prepare your Node.js application.
  • azure/login@v1 uses the AZURE_CREDENTIALS secret (a JSON object containing your Service Principal details) to authenticate.
  • azure/webapps-deploy@v2 is configured with your app-name and the package containing your built application files.

Internal Mechanics of App Service Deployment:

When azure/webapps-deploy runs, it doesn’t just copy files. It interacts with the Azure App Service platform’s deployment engine. For many deployment types (like Zip Deploy, which this action often uses), it uploads a .zip archive of your package directory to a staging slot on the App Service. The App Service then unpacks this archive into the wwwroot directory of your application. If you’re using deployment slots, it might deploy to a staging slot first, and then swap it into production.

The "package" parameter is crucial. It tells the action what to deploy. If your build process outputs files into a build folder, you’d set package: 'build'. If it’s a single .jar file, you might point to that directly. The action then zips up the contents of this specified directory.

The core of the deployment is the interaction with the Kudu service, the engine behind App Service deployments. Kudu handles the unpacking, and for certain languages (like Node.js, Python, PHP), it can also run post-deployment scripts or install dependencies based on configuration files (like package.json or requirements.txt) found in the deployed package.

What most people don’t realize is that the azure/webapps-deploy action, by default, performs a "Zip Deploy." This means it takes the directory specified by package, creates a zip archive of its contents, and uploads that archive. App Service then extracts this archive into the wwwroot folder. This is generally efficient, but it means that any files not included in that package directory (e.g., source maps if they aren’t in your build output, or other project files) will not be present on the App Service.

The next concept you’ll likely grapple with is managing environment-specific configurations for your deployed application, especially when dealing with multiple deployment slots.

Want structured learning?

Take the full Github course →