Introduction
"Think globally, act locally" – this is the heart of what Act enables. Ever feel the pain of commit-push, commit-push, testing your GitHub Actions? Well, this tool is for you. In this tutorial, you're going to learn why running GitHub Actions locally will speed up your development and make things much more efficient.
Steps we will cover in this article:
Why Run GitHub Actions Locally?
There are two main reasons why running GitHub Actions locally can be a game changer:
1. Fast Feedback
Instead of pushing changes to GitHub every single time you want to test an update in your .github/workflows/ files, with Act you can run these actions locally. This tool actually emulates the environment GitHub uses, replicating both the variables and the filesystem, so then you can quickly test changes. This will really speed up your feedback loop and save some time and energy.
2. A Better Local Task Runner
If you enjoy working with tools like make, but are frustrated having to duplicate effort between your task runner and GitHub Actions, Act is a fantastic option. In it, you can utilize the GitHub Actions already defined in your .github/workflows/ as your local task runner, so there is no real need to maintain a Makefile. This cuts repetition and aligns workflows.
Installation
To get started using act, you’ll need to install the tool on your local machine. You can find how to do it for your operating system in the official Installation doc.
as a GitHub CLI Extension
Act installed as an extension is a neat way to incorporate it into your workflow if you use the GitHub CLI already. This makes running GitHub Actions locally even easier, since it is integrated into your existing GitHub CLI commands.
To install act as a GitHub CLI extension, execute:
gh extension install https://github.com/nektos/gh-act
Other installation methods
# Homebrew
brew install act
# Arch Linux
yay -Syu act
# COPR
dnf copr enable goncalossilva/act
dnf install act-cli
# Windows
choco install act-cli
# MacPorts
sudo port install act
# Nix
nix-env -iA nixpkgs.act
# Scoop
scoop install act
# Winget
winget install nektos.act
How to Use act
Basic Usage: Running Workflows Locally
Once installed, you can start running your GitHub Actions locally. By default, act will trigger the push event, but you are able to specify other events too.
act push
This runs all workflows that are triggered by the push event.
For other events, like pull_request
or schedule
:
act pull_request
act schedule
To list all the workflows for a given event, you can use:
act -l pull_request
Running Workflows with Custom Event Payloads
Depending on the workflows you have, some event properties may be required. For example, a pull request event may have head_ref
and base_ref
values. You can provide these properties with a custom event file like this:
{
"pull_request": {
"head": {
"ref": "sample-head-ref"
},
"base": {
"ref": "sample-base-ref"
}
}
}
For the tagged push
event, your event file would look like this:
{
"ref": "refs/tags/this-is-a-tag"
}
Run the event with:
act -e event.json
Working with Workflows
By default, act runs all workflows that it finds in .github/workflows/
. If you would like to run specific workflows or override this behavior, you can specify the exact workflow or directory:
act -W '.github/workflows/'
This will trigger all the jobs placed in .github/workflows
via a push event.
Alternatively, you could run a specific workflow file by running:
act -W '.github/workflows/checks.yml'
Running Specific Jobs
To run a specific job from a workflow, you’ll want to use the -j
flag:
act -j 'test'
This will execute the job named test
in all workflows triggered by the push
event.
Configuration Files with .actrc
You can configure act using .actrc
files, which let you specify common arguments. These should be present in directories and must be one argument per line.
Example .actrc
file:
--container-architecture=linux/amd64
--action-offline-mode
Working with Vars and Secrets
act allows you to pass repository variables and secrets for workflows. You can pass them interactively or load them from a file.
For variables, use:
act --var VARIABLE=somevalue
act --var-file my.variables
For secrets, use:
act -s MY_SECRET=somevalue
act --secret-file my.secrets
Be careful not to enter sensitive information, as it might be stored in terminal history. Use secure methods for input or prefix your command with a space.
Using GITHUB_TOKEN
Many workflows depend on the GITHUB_TOKEN
GitHub provides. If you are experiencing issues with token authentication, you should create a personal access token and provide it as a secret:
act -s GITHUB_TOKEN=[your token here]
You can also use the GitHub CLI to automatically pass the token:
act -s GITHUB_TOKEN="$(gh auth token)"
Skipping Jobs and Steps Locally
You can bypass certain jobs or steps when running act locally. For jobs, use the if
condition with a custom event property:
jobs:
deploy:
if: ${{ !github.event.act }} # Skip during local actions testing
For steps, use the ACT
environment variable:
steps:
- name: Some step
if: ${{ !env.ACT }}
Manually Triggering Workflows with Inputs
You can pass inputs when manually triggering workflows via the CLI:
act --input NAME=somevalue
act --input-file my.input
The input file format is the same as .env
.
Alternatively, you can provide a JSON file:
{
"inputs": {
"NAME": "Manual Workflow",
"SOME_VALUE": "ABC"
}
}
Trigger with:
act workflow_dispatch -e payload.json
Using Matrix Configurations
To run a specific subset of matrix configurations, use the --matrix
flag. For example, to run the workflow for node 8
:
act push --matrix node:8
This will trigger the workflow for os: ubuntu-18.04
and node: 8
.
Action Offline Mode
To speed up running act and use cached actions and containers, enable offline mode:
act --action-offline-mode
This will prevent pulling existing images and actions from GitHub if they’re cached locally. It’s particularly helpful when dealing with network or rate-limiting issues.
Runners
with act for Local GitHub Actions
When using act to run workflows locally, the tool must simulate the GitHub runner environments defined in your workflow files. It does this by using specific Docker images for each type of runner that act leverages to instantiate a container. A quick summary of the most commonly used runner images follows:
GitHub Runner | Micro Docker Image | Medium Docker Image | Large Docker Image |
---|---|---|---|
ubuntu-latest | node:16-buster-slim | catthehacker/ubuntu:act-latest | catthehacker/ubuntu:full-latest |
ubuntu-22.04 | node:16-bullseye-slim | catthehacker/ubuntu:act-22.04 | catthehacker/ubuntu:full-22.04 |
ubuntu-20.04 | node:16-buster-slim | catthehacker/ubuntu:act-20.04 | catthehacker/ubuntu:full-20.04 |
ubuntu-18.04 | node:16-buster-slim | catthehacker/ubuntu:act-18.04 | catthehacker/ubuntu:full-18.04 |
Without Docker
If you’re working with Windows or macOS and running act on a similar environment, you can skip using Docker by running workflows directly on the host system:
act -P ubuntu-latest=-self-hosted
act -P windows-latest=-self-hosted
act -P macos-latest=-self-hosted
Alternative Images
For a more complete GitHub Actions experience, you may want to use alternative runner images that closely match GitHub’s default environments:
- nektos/act-environments-ubuntu:18.04: A large, 18GB+ image that closely replicates GitHub's runner environment.
- catthehacker/ubuntu:full-*: Full filesystem dumps of GitHub runners.
To use a specific Docker image for your runner, you can specify it with the -P
option:
act -P ubuntu-18.04=nektos/act-environments-ubuntu:18.04
For multiple platforms, list each platform with its corresponding image:
act -P ubuntu-18.04=nektos/act-environments-ubuntu:18.04 -P ubuntu-latest=ubuntu:latest -P ubuntu-16.04=node:16-buster-slim
with Local Docker Images
By default, act pulls the required Docker images when running workflows. If you want to use a local image or avoid pulling new images every time, you can disable the pull behavior:
act --pull=false
Alternatively, you can enable offline mode to avoid pulling images:
act --action-offline-mode
Unsupported Features in act
While act is a powerful tool to run GitHub Actions locally, there are certain limitations due to design choices and because of available resources. Here’s a list of key features that are either planned for a future implementation or will not be supported:
Features Not Yet Supported (Planned)
- Services: Support for services like databases is not yet available. (Issue #173)
- Concurrency: Workflow concurrency is currently ignored.
- run-name: This field is ignored, meaning you can't customize the name of a workflow run.
- Step Summary: Summary output for steps is not processed.
- Problem Matcher: Pattern matching for errors and warnings in logs is not supported.
- Annotations: Workflow annotations are ignored.
- vars Context: The vars context is not implemented, so variables defined this way cannot be used.
- Incomplete github Context: Not all elements of the GitHub context are fully supported.
- Run Steps Cancellation: Canceling running steps mid-execution isn't available.
- Permissions:
job.permissions
are ignored, meaning that permission scopes for jobs aren’t respected. - Timeouts and Continue on Error:
timeout-minutes
andjob.continue-on-error
are not implemented.
Known Limitations
- PATH for Node.js Actions: The container or act environment must include
node
for Node.js-based actions. GitHub's runners have their own copy of Node.js for both the container and host. - OpenID Connect: OpenID Connect URL support isn't available.
- job.environment: Scoping secrets by deployment environment is not supported, and
job.environment
is ignored.
Conclusion
act is worth adding to your toolset.
Running GitHub Actions locally with act provides a two orders of magnitude increase in your development velocity because you will get fast feedback, and you won’t be stuck repeatedly committing and pushing. Besides testing changes in your workflows, act can be used as a local task runner, giving flexibility and efficiency in how you manage CI/CD pipelines.