goyek (/ˈɡɔɪæk/ 🔊 listen) is a task automation library intended to be an alternative to Make, Mage, Task.
The primary properties of goyek are:
- Library, not an application, with API inspired by
testing,cobra,flag,http. - Cross-platform and shell independent.
- No binary installation needed.
- Easy to debug, like regular Go code.
- Tasks are defined similarly to
cobracommands. - The task action looks like a Go test.
goyek.Ahas similar methods totesting.T. - Reuse any Go code and library e.g.
viper. - Highly customizable.
- Zero third-party dependencies.
- Additional features in
goyek/x.
5-minute video: Watch here (Slides).
Please ⭐ Star this repository if you find it valuable.
For build automation, store your code in the build directory.
The following example defines a simple hello task that logs a message
and prints the Go version.
Create build/hello.go:
package main
import (
"flag"
"github.com/goyek/goyek/v3"
"github.com/goyek/x/cmd"
)
var msg = flag.String("msg", "greeting message", "Hello world!")
var hello = goyek.Define(goyek.Task{
Name: "hello",
Usage: "demonstration",
Action: func(a *goyek.A) {
a.Log(*msg)
cmd.Exec(a, "go version")
},
})Create build/main.go:
package main
import (
"os"
"github.com/goyek/goyek/v3"
"github.com/goyek/x/boot"
)
func main() {
if err := os.Chdir(".."); err != nil {
panic(err)
}
goyek.SetDefault(hello)
boot.Main()
}The packages from github.com/goyek/x
are used for convenience.
Run help:
cd build
go mod tidy
go run . -hExpected output:
Usage of build: [tasks] [flags] [--] [args]
Tasks:
hello demonstration
Flags:
-dry-run
print all tasks without executing actions
-long-run duration
print when a task takes longer (default 1m0s)
-msg string
Hello world! (default "greeting message")
-no-color
disable colorizing output
-no-deps
do not process dependencies
-skip comma-separated tasks
skip processing the comma-separated tasks
-v print all tasks as they are run
Run with verbose output:
go run . -vExample output:
===== TASK hello
hello.go:16: greeting message
hello.go:17: Exec: go version
go version go1.24.0 linux/amd64
----- PASS: hello (0.12s)
ok 0.123s
Instead of running go run . inside build, you can use wrapper scripts:
Use goyek/template when creating
a new repository. For existing repositories, simply copy the relevant files.
See the documentation for more information.
The following repositories demonstrate real-world usage of goyek:
- goyek/template: a Go application repository template using goyek for build automation.
- build/: this repository dogfoods goyek for its own build pipeline.
- splunk-otel-go: a multi-module repository using goyek.
- curioswitch/go-build and projects such as curioswitch/tasuke: an example of extracting reusable build tasks into a shared module consumed by multiple repositories.
- Keep build code in
build/: place your automation in a dedicatedbuilddirectory or module so it stays separate from application code. - Define tasks at startup: register tasks with
goyek.Defineduring package init, before callingMainorExecute, and avoid mutating task definitions afterwards. - Use
*goyek.Afor control flow: prefera.Log,a.Error,a.Fatal,a.Skip,a.Cleanup, anda.Contextover manuallogoros.Exitcalls. - Prefer helpers for external commands: use
github.com/goyek/x/cmd.Execor a small helper (like this repo'sbuild/exec.go) instead of callingos/execdirectly in actions. - Structure pipelines with dependencies: keep actions small and compose
them with
Depsrather than writing one large, monolithic task. - Use middlewares for cross-cutting concerns: plug in middlewares such as
middleware.ReportStatus,middleware.ReportLongRun,middleware.DryRun,middleware.BufferParallel, or custom ones viagoyek.Useandgoyek.UseExecutor. - Be deliberate with parallelism: set
Task.Parallelonly when actions are safe to run concurrently and rely onmiddleware.BufferParallelto keep output readable. - Treat context and cleanup carefully: start long-running resources using
a.Context()and release them ina.Cleanupcallbacks, keeping in mind that the task context is canceled before cleanups run. - Reuse tasks across repositories: extract common tasks into a shared
module (as in
curioswitch/go-build) and import them from other projects to keep build logic consistent.
goyek was originally built as a small library for expressing Go build pipelines in Go itself instead of relying on an external DSL or tool. Keeping build logic as regular Go code makes it easy to reuse existing packages, refactor with IDE support, and debug tasks with the standard Go toolchain.
Although build automation remains the primary use case, goyek is designed as a general task runner. Tasks are ordinary Go functions wired together through dependencies, which makes it suitable for other domains as well. It is known to be used, for example, by SRE and platform teams to automate deployment pipelines and other operational workflows.
Compared to Make and similar tools, goyek does not require learning a separate DSL or shell tricks and makes it easier to keep pipelines portable across platforms. Unlike Mage, it avoids build tags, code generation, and magic discovery of targets – you just write and compose ordinary Go functions. In contrast to Task, there is no YAML to learn or additional binary to install, and debugging tasks is like debugging any other Go program. Finally, while systems such as Bazel focus on large, hermetic build graphs, goyek deliberately stays small and library‑like, so you can start with a simple build script and grow into more advanced pipelines only when needed.
We welcome contributions! See CONTRIBUTING.md for details.
goyek is licensed under the terms of the MIT license.
Note: goyek was named taskflow before v0.3.0.