Testing GitHub Actions Locally with Act
by Gary Worthington, More Than Monkeys

GitHub Actions are brilliant for automating CI/CD, but they have one annoying trait — you often don’t know if your workflow works until you push a commit and wait for the cloud runner to do its thing.
That means:
- Pushing half a dozen commits with “fix workflow” in the message.
- Waiting minutes for every small syntax change.
- Burning through build minutes on private repos.
If you’ve been there, you know how tedious it is. This is where Act comes in.
What is Act?
Act is an open-source tool that lets you run your GitHub Actions workflows locally. It uses Docker to simulate the GitHub Actions environment, so you can test and debug your workflows before pushing to GitHub.
You can think of it like a local CI runner for your .github/workflows files.
Why Bother Testing Locally?
There are three main reasons:
- Speed — Running jobs locally can cut feedback from minutes to seconds.
- Iteration — You can tweak and rerun without spamming commits.
- Cost — For private repos, fewer runs in GitHub’s cloud means fewer minutes used.
If your workflow involves deploying infrastructure or running long build jobs, testing locally can save you serious time and money.
Installing Act
Act requires Docker. Make sure you have Docker running before you start.
On macOS with Homebrew:
brew install act
On Linux:
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
Or grab a binary from the releases page.
Running a Workflow Locally
Let’s say you have a basic workflow in .github/workflows/test.yml:
name: Run Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests
run: pytest
Normally, you’d push a commit and wait for GitHub Actions to run this. With Act:
act push
That runs the push event locally using Docker, giving you instant feedback.
Choosing Runners
GitHub runners come in flavours like ubuntu-latest, windows-latest, or macos-latest. Act uses Docker images to simulate them.
The default image is small and fast, but it may not have all the tools your workflow needs. You can specify a different image:
act push -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest
This uses a fuller Ubuntu image with more pre-installed tools.
Passing Secrets
Most workflows need secrets: API keys, tokens, or credentials. Act can load these from a file.
Create .secrets:
MY_API_KEY=abc123
ANOTHER_SECRET=xyz789
Run with:
act push --secret-file .secrets
Secrets are then available to your workflow exactly as they would be in GitHub Actions.
Using Matrix Builds
If your workflow uses a build matrix, Act can handle that too.
Example:
strategy:
matrix:
python-version: [ "3.9", "3.10", "3.11" ]
Run:
act push
You’ll see Act run each matrix combination locally.
Debugging with Logs
Act shows workflow logs directly in your terminal. If a step fails, you can quickly edit the workflow or scripts and re-run without pushing commits.
For verbose logging:
act push --verbose
This is especially useful for spotting YAML mistakes or missing dependencies before they hit GitHub.
Limitations and Gotchas
Act is powerful, but it’s not a perfect replica of GitHub’s environment:
- Some GitHub-hosted services (like Actions cache or certain runners) are not fully simulated.
- Docker-in-Docker can be tricky on some platforms.
- Large images can slow down the first run.
That said, for most build, test, and lint pipelines, Act gets you very close to production.
Real-World Example: Python Package CI
Here’s a complete Python CI pipeline that I run locally with Act before pushing:
name: Python CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.10", "3.11" ]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: pip install -r requirements.txt
- run: pytest --maxfail=1 --disable-warnings -q
Run it locally:
act push
If tests pass locally, I’m confident they’ll pass in GitHub Actions.
My Workflow for Workflow Development
When building or updating GitHub Actions pipelines, my process is:
- Write or edit the workflow YAML in .github/workflows.
- Run locally with Act until it’s passing.
- Commit and push to GitHub.
- Review in GitHub Actions UI for the final confirmation.
This cuts my iteration time from 5–10 minutes per change to seconds.
The Bottom Line
GitHub Actions are great, but the push–wait–debug cycle can slow you down. Act gives you instant feedback, local debugging, and lower costs.
If you want to ship faster, reduce noise in your commit history, and keep your CI green, testing with Act is a no-brainer.
Next Step: Install Act, run your workflow locally, and see how much faster you can iterate.
If you’re building complex CI/CD pipelines and want to tighten your feedback loops, this approach will pay for itself on the first project.
Gary Worthington is a software engineer, delivery consultant, and agile coach who helps teams move fast, learn faster, and scale when it matters. He writes about modern engineering, product thinking, and helping teams ship things that matter.
Through his consultancy, More Than Monkeys, Gary helps startups and scaleups improve how they build software — from tech strategy and agile delivery to product validation and team development.
Visit morethanmonkeys.co.uk to learn how we can help you build better, faster.
Follow Gary on LinkedIn for practical insights into engineering leadership, agile delivery, and team performance