When building a new GitHub Action, repeatedly testing on GitHub is slow. With act you can validate locally to some extent and then run it on GitHub.
Installation
Requires a Docker environment.
On macOS:
brew install actIf Go is installed (non‑Mac as well):
go install github.com/nektos/act@latestOn Apple Silicon (M1/M2), pass --container-architecture linux/amd64.
You may hit this yarn issue:
Specify a platform with -P/--platform; as in the issue, -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:js-latest allowed yarn to run.
Put these in ~/.actrc so you don’t have to type them every time:
--container-architecture linux/amd64
-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:js-latestBasic usage
With no args, act runs workflows triggered by push:
actTo trigger a pull_request workflow:
act pull_requestList workflows for an event
Add -l/--list after the event:
act pull_request -l
Stage Job ID Job name Workflow name Workflow file Events
0 helloworld helloworld Hello World helloworld.yaml pull_requestRun a specific workflow
Use -W/--workflows to point to a file:
act -W .github/workflows/helloworld.yaml pull_requestSimulate merging a Pull Request locally
Create a test workflow that prints “hello world” on merge (.github/workflows/helloworld.yaml):
name: Hello World
on:
pull_request:
types: [closed]
jobs:
hello-world:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- run: echo "Hello World!"Running locally now fails because the event payload is missing:
act -W .github/workflows/helloworld.yaml pull_request
Error: ❌ Error in if-expression: "if: github.event.pull_request.merged == true" (Unable to dereference 'merged' on non-struct 'invalid')Work around this by providing an event JSON via -e/--eventpath.
cat pull_request.json
{
"pull_request": {
"merged": true
}
}
act -W .github/workflows/helloworld.yaml pull_request -e pull_request.json
[Hello World/hello-world] 🚀 Start image=ghcr.io/catthehacker/ubuntu:js-latest
...
| Hello World!
[Hello World/hello-world] ✅ Success - echo "Hello World!"If you change merged to false in pull_request.json, it won’t run.