← All articles
text

act: Run GitHub Actions Locally Without Pushing to GitHub

CI/CD 2026-03-12 · 4 min read github-actions ci-cd developer-tools docker testing

If you've ever pushed a commit just to test a GitHub Actions workflow change, you know the pain: wait for a runner, watch it fail on line 3 of your YAML, fix it, push again, repeat. act breaks this loop by running your workflows locally in Docker containers that mirror the GitHub environment.

Photo by Laine Cooper on Unsplash

What act Does

act reads your .github/workflows/*.yml files and runs them locally. It pulls the same runner images GitHub uses (or lightweight alternatives), sets up the same environment variables, and executes your steps using the same action syntax.

The result: a tight feedback loop. A workflow that would take 5 minutes on GitHub to test a 3-line YAML change can be verified in seconds locally.

Installation

The fastest way on macOS is Homebrew:

brew install act

On Linux, use the install script:

curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash

Or install via GitHub releases directly. If you use mise or asdf, act is available there too:

mise use act

Basic Usage

Run all workflows triggered by the push event:

act push

Run a specific workflow by name:

act push -W .github/workflows/ci.yml

Run a specific job within a workflow:

act push -j build

List all available workflows and jobs without running them:

act -l

Runner Images

The first time you run act, it asks which runner size to use:

For most CI pipelines, the medium image works fine. For workflows that depend on pre-installed tools like specific Python versions or system packages, you may need the large image.

You can set a default in ~/.config/act/actrc:

-P ubuntu-latest=catthehacker/ubuntu:act-latest

Or specify per-run with -P:

act -P ubuntu-latest=catthehacker/ubuntu:act-latest push

Secrets and Environment Variables

Workflows that reference ${{ secrets.MY_SECRET }} need values locally. Pass them with --secret:

act push --secret MY_SECRET=value

Or use a .secrets file (similar to .env):

MY_SECRET=value
ANOTHER_SECRET=other-value
act push --secret-file .secrets

Add .secrets to your .gitignore. Never commit real credentials.

For environment variables (not secrets), use --env or a .env file:

act push --env NODE_ENV=test

Handling Common Failures

Actions that require GitHub tokens: Some actions need GITHUB_TOKEN for API access. Pass a personal access token:

act push -s GITHUB_TOKEN=ghp_yourtoken

Platform mismatches: act runs Docker containers on your host, so runs-on: macos-latest won't work on Linux. You can override the runner mapping for platform-specific jobs:

act push -P macos-latest=ubuntu-latest

This lets the workflow run on an Ubuntu container even if it specifies macOS. Jobs with macOS-specific commands will fail, but you can still test the platform-agnostic steps.

Docker-in-Docker: Workflows that build and push Docker images need privileged mode. Enable it with --privileged:

act push --privileged

github.event context: Local runs don't have a real GitHub event payload. act injects a synthetic payload, but some workflows inspect github.event.pull_request or similar fields. You can provide a custom event JSON:

act pull_request -e event.json

Where event.json contains a mock payload matching the event schema.

Workflow for Debugging CI

A typical debugging session looks like this:

  1. A workflow fails on GitHub. You look at the logs, spot the issue.
  2. Edit the workflow YAML locally.
  3. Run act push -j failing-job to test the fix.
  4. Iterate until act shows green.
  5. Push the fix. One commit, one verify.

This is dramatically faster than the push-wait-read-push cycle, especially for multi-step workflows where failures happen deep in the pipeline.

Caching and Artifacts

act supports the actions/cache action with a local cache directory. Enable it by mounting a cache path:

act push --artifact-server-path /tmp/act-artifacts

For actions/upload-artifact and actions/download-artifact, act runs a local artifact server. Files are saved to the specified path instead of GitHub's artifact storage.

Limitations

act is excellent for most workflows but has real gaps:

For these cases, a short "sanity run" with act still catches most issues before the real push. Save the platform-specific testing for GitHub.

Practical Configuration

Keep a .actrc in your repo root for project-specific defaults:

-P ubuntu-latest=catthehacker/ubuntu:act-22.04
--secret-file .secrets
--env-file .env.test

Now running act push automatically uses your preferred image and picks up local secrets without extra flags.

When to Use act

If your team pushes "fix CI" commits more than once per change, act is worth the 20 minutes it takes to set up. The feedback loop improvement compounds across every CI iteration from that point forward.