Blog Post

Azure Infrastructure Blog
7 MIN READ

Using Act to Test GitHub Workflows Locally for Azure Deployments (CI/CD)

BiprojitDey's avatar
BiprojitDey
Icon for Microsoft rankMicrosoft
May 15, 2025

GitHub Actions is a widely used platform that helps developers automate software workflows, including CI/CD pipelines and testing processes. However, testing and refining these workflows directly on GitHub can be cumbersome, especially when debugging complex actions. This is where the act tool proves valuable, it allows developers to run GitHub Actions locally, providing a more convenient way to test and iterate on workflows before pushing them to GitHub.

What Is Act

Act is an open-source CLI tool (by nektos) that lets you run GitHub Actions workflows entirely on your local machine. When you invoke act, it reads your workflow files under .github/workflows/ and uses Docker to simulate the GitHub Actions environment In practice, Act “spins up” each job inside a Docker container as if it were running on GitHub, complete with the same environment variables and file system layout This means you can run pushpull_request, or any triggered workflow locally without ever pushing to GitHub. As one author summarized, Act’s goal is to run GitHub Actions in containers locally while handling env variables and secrets just like GitHub does (“Think globally, act locally”).

Benefits of Using Act

Running workflows locally with Act offers several major advantages to developers:

  • Fast Feedback Loop: You avoid the commit–push cycle. Instead of waiting for GitHub’s cloud runners, you get immediate results. In fact, by using Act you can skip pointless commits to test changes, dramatically accelerating development.
  • Efficient Debugging: Because Act closely mimics GitHub’s environment, bugs that would cause CI failures can be caught and fixed locally. This reduces the risk of broken pipelines. For example, one developer noted that having to “merge untested workflows” often leads to failures; Act removes that uncertainty.
  • Resource Savings: Local runs don’t consume GitHub Actions minutes or build minutes. Especially on paid plans or heavy workloads, this can save costs. In fact, Act explicitly advertises that it “runs workflows locally, saving time and GitHub Actions minutes.
  • Offline and Local Tasks: You can work even offline (assuming Docker images are cached), and use GitHub Actions just like a local task runner (similar to using a Makefile). This also means faster prototyping and avoiding costly cloud operations until you’re ready.
  • Environment Simulation: act simulates the GitHub Actions runner environment, ensuring that workflows run as if they were executed on GitHub
  • Consistency: Because Act uses containers, your local testing environment can exactly match the GitHub runner (by selecting the same base image, e.g. ubuntu-latest). This avoids “works on my machine” issues and ensures the environment is replicated locally.
  • Secrets and Environment Variables: Secrets and environment variables can be passed effortlessly to workflow with act, perfectly emulating the GitHub environment.

Installation and Prerequisites

Before using Act, you need to install the Act CLI and ensure Docker is available:

  • Download Act directly from [GitHub releases]: Download here

  • Install Act CLI:
    • macOS/Linux: The easiest way is via Homebrew (brew install act). Alternatively, download the binary from the GitHub releases page or run the official install script: 
      curl -sSf https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash

       

    • Windows: You can install via Chocolatey (choco install act-cli) or Scoop (scoop install act), or manually download the executable and add it to your PATH.
  • Docker: Act depends on Docker Engine to run workflows in containers. Install Docker Desktop on macOS/Windows or Docker Engine on Linux. (If you do not require container isolation, Act can optionally run some jobs directly on the host system, but Docker is the standard mode.)
  • VS Code Extensions: For a better experience, install the GitHub Actions and GitHub Local Actions extensions in Visual Studio Code. The first adds YAML validation and snippets for Actions. The GitHub Local Actions extension integrates Act directly into the editor. It provides UI commands to run workflows or jobs, trigger events, and manage secrets/inputs.

After installation, verify with:

act --version # should show v0.x.x

How to Use Act

1. Navigate to Your Project Repository

Ensure you're inside a Git repository that has a .github/workflows/ directory with valid workflow .yml files.

2. Run Workflows

To run all default workflows:

act

Dryrun: print steps without executing

act --dryrun

To simulate a push event:

act push

List jobs without executing:

act -l push

To run a specific job in a workflow:

act -j <job-name>

You can also specify the event file (simulating GitHub event payloads):

act pull_request -e event.json
3. Using Secrets

Inject secrets into the environment:

act -s MY_SECRET=value

You can load multiple secrets via .secrets file:

MY_SECRET=value
ANOTHER_SECRET=another

And run with:

act --secret-file .secrets
4. Use Custom Docker Image (Optional)

For more compatibility with GitHub runners:

act -P ubuntu-latest=nektos/act-environments-ubuntu:20.04
5. Clean Up Containers

To remove any containers created by act:

docker ps -a  # find container ID
docker rm <container-id>

Advanced act Usage

1. Utilizing Custom Docker Images

For workflows requiring specific environments, act allows the use of custom Docker images. You can specify these images in a .actrc file:

echo "-P ubuntu-latest=nektos/act-environments-ubuntu:18.04" > ~/.actrc

This configuration ensures that act uses the specified Docker image, aligning the local testing environment with your production setup

2. Specifying GitHub Event Payloads

To simulate specific GitHub events locally, you can provide a custom event payload using the -p option:

act push -p event.json

This approach is particularly useful when testing workflows that depend on specific event data, such as pull requests or issue comments.

3. Specifying Workflows & Jobs

Run only one workflow file (deploy.yml) on push:

act -W .github/workflows/deploy.yml

Execute only a specific job by name:

act -j build-and-test
4. Secrets Management
  • Inline: act -s AZURE_TOKEN=XXXX
  • Prompted: act -s DOCKERHUB_TOKEN
  • File-based: act --secret-file ./local-secrets.env

local-secrets.env:

AZURE_CLIENT_ID=abc
AZURE_TENANT_ID=xyz
AZURE_SUBSCRIPTION_ID=0000-1111-2222-3333
AZURE_RESOURCE_GROUP=myRG
AZURE_CREDENTIALS={...}

Azure-Focused Workflow Examples (Modular Cases)

Below are small, focused YAML snippets illustrating common Azure deployment steps. Each can be tested independently with Act.

Azure Login
- name: Azure Login
  uses: azure/login@v2
  with:
    client-id: ${{ secrets.AZURE_CLIENT_ID }}
    tenant-id: ${{ secrets.AZURE_TENANT_ID }}
    subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

Test with Act:

act -s AZURE_CLIENT_ID=... -s AZURE_TENANT_ID=... -s AZURE_SUBSCRIPTION_ID=...

Deploy ARM/Bicep Template

- name: Deploy Infrastructure
  uses: azure/arm-deploy@v1
  with:
    subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
    resourceGroupName: ${{ secrets.AZURE_RESOURCE_GROUP }}
    template: ./infra/main.bicep
    parameters: |
      location=eastus
      appServicePlanName=myPlan

Test with Act:

act -s AZURE_SUBSCRIPTION_ID=... -s AZURE_RESOURCE_GROUP=... --dryrun
Deploy Azure Functions
- name: Build Function App
  run: |
    cd function-app
    npm install && npm run build

- name: Deploy Function App
  uses: Azure/functions-action@v1
  with:
    app-name: my-func-app
    package: './function-app/dist'

Test with Act:

act
AKS Context & Kubernetes Deploy
- name: Configure AKS Context
  uses: azure/aks-set-context@v1
  with:
    creds: ${{ secrets.AZURE_CREDENTIALS }}
    resource-group: ${{ secrets.AZURE_RESOURCE_GROUP }}
    cluster-name: ${{ secrets.AZURE_AKS_NAME }}

- name: Apply Kubernetes Manifests
  run: kubectl apply -f ./k8s/

Test with Act:

act -s AZURE_CREDENTIALS='{}'  # Use empty creds to validate syntax

Example CI/CD Pipeline for Act

Here's a comprehensive CI/CD pipeline example that you can test locally with Act:

name: Azure CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  ci:
    name: Build and Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
          
      - name: Install Dependencies
        run: npm ci
        working-directory: ./function-app
        
      - name: Run Tests
        run: npm test
        working-directory: ./function-app
        
      - name: Run Linting
        run: npm run lint
        working-directory: ./function-app
        
      - name: Build Function App
        run: npm run build
        working-directory: ./function-app
        
      - name: Upload Build Artifact
        uses: actions/upload-artifact@v3
        with:
          name: function-app-dist
          path: ./function-app/dist
          retention-days: 1

  cd:
    name: Deploy to Azure
    needs: ci
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Download Build Artifact
        uses: actions/download-artifact@v3
        with:
          name: function-app-dist
          path: ./function-app/dist
      
      - name: Azure Login
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      
      - name: Deploy Infrastructure
        uses: azure/arm-deploy@v1
        with:
          subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
          resourceGroupName: ${{ secrets.AZURE_RESOURCE_GROUP }}
          template: ./infra/main.bicep
          parameters: |
            location=eastus
            appServicePlanName=myPlan
            functionAppName=my-func-app
      
      - name: Deploy Function App
        uses: Azure/functions-action@v1
        with:
          app-name: my-func-app
          package: './function-app/dist'
Testing with Act

Test CI Only

act pull_request --job ci

Test CD Only (with secrets)

act push --job cd -s AZURE_CLIENT_ID=your-client-id -s AZURE_TENANT_ID=your-tenant-id -s AZURE_SUBSCRIPTION_ID=your-subscription-id -s AZURE_RESOURCE_GROUP=your-resource-group

Test Entire Pipeline

act push -s AZURE_CLIENT_ID=your-client-id -s AZURE_TENANT_ID=your-tenant-id -s AZURE_SUBSCRIPTION_ID=your-subscription-id -s AZURE_RESOURCE_GROUP=your-resource-group

 

Estimated Time Savings

Using act can dramatically reduce the feedback loop when developing and debugging GitHub Actions workflows. Here's how:

  • Faster Workflow Testing: A typical cloud-based workflow run can take 2–5 minutes, while act executes similar workflows in 5–20 seconds, depending on complexity and Docker image caching.
  • Reduced Wait Time: Skip GitHub's queuing delays and instantly validate logic locally.
  • Cost Efficiency: Decrease CI minutes used on GitHub, especially valuable for teams on limited usage plans.

Cumulatively, teams report 70–90% reduction in total workflow-debug time by shifting initial iterations to Act. Over dozens of runs, this saves hours per sprint.

Conclusion

act empowers developers to test GitHub Actions workflows locally with speed, precision, and reduced overhead. For Azure-focused teams, this becomes especially impactful streamlining infrastructure deployments, Bicep/ARM template testing, and Function App rollouts testing directly from the local environment. It enables developers to validate infrastructure-as-code changes instantly without consuming GitHub CI minutes or waiting for cloud runners. By integrating act into your workflow, you not only accelerate development but also build with greater confidence, reliability, and efficiency crucial for modern DevOps on Azure

Updated May 15, 2025
Version 1.0
No CommentsBe the first to comment