Stephan Schmidt - August 14, 2025
Build Tools for Go
Comparing make, XC, bazel, mage and taskfile
TL;DR: For Go projects, start with native `go build` commands and only add a build tool when you need to orchestrate multiple tasks like testing and linting—Makefile works for most teams, but specialized options like mage (Go-based), Taskfile (YAML), or goreleaser (multi-platform releases) exist if you need more power or prefer different configuration styles.
Programming languages have their build tools. Java has Maven, Scala has SBT, and Javascript has NPM beside many web build tools. Newcomers to Golang wonder about the build tool for Go. Starting is easy, the go compiler is easier to use than comparable alternatives, to start no build tool is necessary.
All of these
go build
go run
go install
do the job.
When you have more than Go code to build, but tests to run, code to lint etc. the newcomer to Golang asks what now?
I’ve started with go build, added bash scripts for linting and deployment and for now I’ve settled with Makefile and make—replacing all bash scripts with make targets.
build: git-hash
templ generate ./...
go build -o bin/ ./...
Here we a have a build target, that depends on another git-hash target. The target needs to generate a-h/templ templates and then build the application. For most people Makefile is enough, it’s easy to use for basic tasks and available on many systems.
Asking around r/Golang, more options popped up:
bazel
bazel was built by Google for large monorepos with many different languages. But works for small projects just fine, and the Go integration seems to be the best language integration in bazel.
goreleaser
Not a build tool for all the project tasks you might have used Makefile for, but a build tool
to build Go for many different platforms and operating system targets. It can cross compile, build for Linux packaging like deb and release to GitHub, beside many more targets.
just
just is inspired by make but tries to make it easier and better.
Taskfile
Another one for a better make: “Task is a task runner / build tool that aims to be simpler and easier to use than, for example, GNU Make.”
It is different because it is using YAML:
version: '3'
tasks:
hello:
cmds:
- echo 'Hello World from Task!'
silent: true
mage
mage uses Go to define build files
//go:build mage
package main
import (
"github.com/magefile/mage/sh"
)
// Runs go mod download and then installs the binary.
func Build() error {
if err := sh.Run("go", "mod", "download"); err != nil {
return err
}
return sh.Run("go", "install", "./...")
}
XC
“The problem xc is intended to solve is scripts maintained separately from their documentation.” So with XC the build file contains its own documentation in Markdown
## tag
Deploys a new tag for the repo.
Requires: test
'''
export VERSION=`git rev-list --count HEAD`
echo Adding git tag with version v0.0.${VERSION}
git tag v0.0.${VERSION}
git push origin v0.0.${VERSION}
'''
script
"script is a Go library for doing the kind of tasks that shell scripts are good at: reading files, executing subprocesses, counting lines, matching strings, and so on."
Can be used together with mage
So go build, then use the one that suits you best—might be plain old make.
About me: Hey, I'm Stephan, I help CTOs with Coaching, with 40+ years of software development and 25+ years of engineering management experience. I've coached and mentored 80+ CTOs and founders. I've founded 3 startups. 1 nice exit. I help CTOs and engineering leaders grow, scale their teams, gain clarity, lead with confidence and navigate the challenges of fast-growing companies.
