# act reproduces GitHub's container contract, not the runner, and its build instructions understate the toolchain

> nektos/act reads your .github/workflows/ files, pulls or builds the images they reference, and runs one container per action with the environment variables and filesystem laid out to match GitHub. It is a Go program that needs Docker at runtime and three toolchains to contribute, and its stated Go floor does not match its go.mod.

**nektos/act** — Run your GitHub Actions locally 🚀

- Repository: https://github.com/nektos/act
- Website: https://nektosact.com
- Stars: 72,124 · Forks: 2,045
- Language: Go
- License: MIT
- Published: 2026-08-04 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/nektos-act

## The build instructions ask for Go 1.20+ and go.mod declares 1.25.0

Read the two version statements against each other before you install anything. The contributing section says to install Go tools 1.20+, clone the repository, run the unit tests with make test, and build and install with make install. The module file says:

```
module github.com/nektos/act

go 1.25.0
```

A toolchain at the stated floor will not build this module. That is a one-line mismatch, and it is the kind that costs an afternoon because the error you get is about the language version rather than about the project.

The install target itself is three steps, and it is worth knowing what they do because the Makefile derives the version rather than reading it from a file. VERSION comes from git describe --tags --dirty --always with a leading v stripped, the build stamps it into the binary with -X main.version, and the install copies the result into place and then runs the binary to prove it works:

```make
.PHONY: install
install: build
	@cp dist/local/act $(PREFIX)/bin/act
	@chmod 755 $(PREFIX)/bin/act
	@act --version
```

PREFIX defaults to /usr/local, which means a stock make install writes outside your home directory and needs the permission to do it.

## act reproduces the environment variables and the filesystem, and nothing else

The mechanism is a four-step pipeline. act reads the workflows in .github/workflows/ and works out which actions need to run. It uses the Docker API to either pull or build the images those workflows define. It resolves the execution path from the dependencies the workflow declares. Then it runs a container per action using the images prepared earlier.

The fidelity claim is scoped, and the scoping is the most important sentence in the project. The environment variables and the filesystem are configured to match what GitHub provides. Nothing is claimed about the rest of the runner. GitHub's own documentation frames hosted runners as virtual environments with a specific filesystem layout, and act's approach is to reproduce that contract inside ordinary Docker containers instead of reproducing a hosted runner environment. That is the whole difference in approach, and it cuts cleanly in two directions.

The benefit is that a step which reads a path or an environment variable behaves the same locally. The cost is that a step relying on a runner capability act does not implement fails as a normal non-zero exit inside a container that started fine. From act's point of view the workflow ran, so the difference between local and hosted shows up as a behavioural discrepancy you have to notice yourself.

## make test runs act against act's own workflows

The test target is not just a Go test run, and this is the first thing to know before you set up a contribution environment:

```make
.PHONY: test
test:
	go test ./...
	$(ACT)
```

ACT defaults to go run main.go, so the second line executes the program under development against the workflows in this repository. In other words the suite contains a self-referential execution of act by act, which means a running Docker daemon, network access to pull the images those workflows reference, and enough time to start containers.

The practical consequence is that a red make test is ambiguous. It might be a failing Go assertion, or it might be a container that would not start, or an image pull that timed out. Anyone who assumes go test ./... is hermetic will be surprised, and anyone bisecting a failure needs to know which of the two halves produced it before they start reading code.

## The pr target needs Go, npx and a megalinter container

Contributing runs a chain rather than a single command, and the chain crosses three toolchains. pr depends on tidy, format-all, lint and test. format-all runs go fmt and then npx prettier --write ., so Node is required. lint depends on lint-go and lint-rest. lint-go is golangci-lint, and lint-rest shells out to Docker:

```make
.PHONY: lint-rest
lint-rest:
	docker run --rm -it \
		-v $(PWD):/tmp/lint \
		-e GITHUB_STATUS_REPORTER=false \
		-e GITHUB_COMMENT_REPORTER=false \
		megalinter/megalinter-go:v5
```

That target mounts your working tree into a container and runs a linter image against it, with the two GitHub reporter variables switched off so the run stays local. Note what the default lint target leaves out: lint-js and lint-md exist as separate targets but are not in it, and make fix runs lint-md and lint-go. So lint, fix and pr do not check the same set of files, and a contributor who runs them in the wrong order gets a different result each time.

For a project this size that is a reasonable trade, but it means the contributor cost is a Go toolchain, a Node toolchain and a container image download before your first patch is testable.

## The Makefile exports a GitHub token from your home directory into the test run

There is a conditional block near the top of the Makefile that is easy to miss and worth reading before you run make on a workstation that has a token file:

```make
HAS_TOKEN = $(if $(test -e ~/.config/github/token),true,false)
ifeq (true,$(HAS_TOKEN))
	export GITHUB_TOKEN := $(shell cat ~/.config/github/token)
endif
```

If the file exists, its contents become GITHUB_TOKEN for every recipe the Makefile runs. That includes the test target, whose second line is $(ACT). So on a machine where that file is present, make test does not merely run the unit tests, it hands your token to the act process and, through it, into the containers that process starts.

This is a contributor-side behaviour, not something that happens when you run the installed act binary yourself, and the repository does not call it out. Two practical consequences: keep that token file off shared or CI images, and know that a token exported this way is in the environment of every container act launches, which is worth remembering when a workflow step prints its environment during debugging. The repository also ships an .actrc file at the root, which is where a project keeps its own act configuration, and that is a separate mechanism from the Makefile.

## Releases land monthly on 0.2.x and master is past the newest tag

The three most recent releases are v0.2.87 on 2026-04-01, v0.2.88 on 2026-05-01 and v0.2.89 on 2026-06-01, all on the first of the month. The last push to the default branch, master, was on 2026-08-09. So the newest tag is roughly two months behind the branch, and the version series has not left 0.2.

That combination sets expectations for anyone pinning the tool. There is no v1.0 to wait for and no compatibility promise attached to a minor bump, so a pin should name an exact 0.2.x tag. The Makefile is built for the in-between case: it treats a version containing a dash as a snapshot, and because it derives the version from git describe, a binary you build from master identifies itself with a described or dirty version rather than a release number. That is useful for telling two builds apart, and useless for filing a bug that says which release you are on.

The other detail worth knowing is how act is packaged. The repository contains install.sh, generated by godownloader from the goreleaser configuration, and act-cli.nuspec, a Windows package specification. Those two artefacts are the distribution surface; there is no package manager entry in the repository, so a Linux install is the shell script or your own build.

## The documentation is a website, and the repository is a pointer to it

The project overview is short, and most of it is a redirect. For anything beyond the two-line summary it sends you to the act user guide at nektosact.com, and for help it points at GitHub discussions. The sample workflow repository it demonstrates against is cplee/github-actions-demo. The editor integration is third-party too: the README promotes the GitHub Local Actions Visual Studio Code extension for running workflows from inside the editor, which is not part of this codebase.

What that leaves inside the repository is thin. There is no flag reference, no configuration reference, and no list of the GitHub Actions features act does not emulate. A configuration file is expected, since .actrc sits at the root, but the repository does not explain what goes in it. IMAGES.md and a VERIFICATION file exist for the images act builds and runs, and neither is explained in the overview.

For a tool whose entire value is fidelity to somebody else's specification, that is the gap to weigh. You can get act running in a few minutes from this README, and you cannot answer the question that determines whether it is trustworthy for your workflow without leaving the repository and reading documentation this project hosts elsewhere.

## Conclusion

Use act for fast feedback on a workflow change and as a stand-in for a Makefile, and do not treat a green local run as evidence that GitHub will behave the same, because act matches the environment variables and filesystem and leaves everything else to the container image. Decline it if you need a hosted-runner feature act does not emulate, since nothing in the repository lists what is missing. Before you build, note that the build instructions ask for Go 1.20+ while go.mod declares go 1.25.0, so install a toolchain at or above 1.25 or the module will not compile. If you contribute, check first that you have Go, npx and a Docker daemon, because the pr target needs all three.

## FAQ

### what is nektos act

act runs your GitHub Actions locally. It reads the workflows in .github/workflows/, uses the Docker API to pull or build the images those workflows reference, resolves the execution order from the dependencies they declare, and then runs a container per action with environment variables and a filesystem configured to match what GitHub provides.

### how to install nektos act

The project's from-source path asks for Go tools, a clone of the repository, `make test` to run the unit tests, and `make install` to build and install. The install target copies the built binary to $(PREFIX)/bin/act, where PREFIX defaults to /usr/local, sets mode 755, and finishes by running `act --version`.

### how to use nektos act

You run act inside a repository that has workflow files under .github/workflows/. It determines which actions need to run, prepares their images through the Docker API, works out the execution path from the declared dependencies, and starts a container for each action. The project points at cplee/github-actions-demo as a sample and at nektosact.com for the user guide.

### nektos act vscode

There is no editor integration in this repository. The project overview points to a third-party Visual Studio Code extension, GitHub Local Actions, which wraps act so you can run and test workflows without leaving the editor.

### nektos act alternative

The project overview links to a community collection of runners at jonico/awesome-runners. The difference in act's own approach is scope: it reproduces GitHub's environment variables and filesystem inside Docker containers rather than reproducing a full hosted runner, so a runner feature act does not emulate appears as a behavioural difference rather than as an error.

## Sources

- [Official documentation](https://nektosact.com)
- [Official README](https://github.com/nektos/act#readme)
- [Project repository](https://github.com/nektos/act)
- [Release notes](https://github.com/nektos/act/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nektos-act
