Self-hosted service
thockin/go-build-template avatar
thockin/go-build-template

thockin/go-build-template: a Makefile and Dockerfile skeleton for Go builds

A Makefile/Dockerfile example for Go projects.

3,333 stars424 forksMakefileApache-2.0

At a glance

What is it?
The repository is a copy-and-edit template that drives Go compilation, testing, linting and multi-architecture image publishing from a single Makefile, and it only claims Linux and Docker buildx support.
Who is it for?
Adopt it if your team already lives in Make and Docker buildx and you want a multi-architecture image pipeline without writing one from scratch. Skip it if you need Windows builds, a non-Docker toolchain, or a project that ships tagged releases, because the repository has none.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Makefile, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: Go builds drift once images and architectures enter the picture

A single go build command is easy. The trouble starts when the same project must produce binaries for several architectures, wrap them in container images, tag those images from git state, push them to a registry, and publish a manifest list that ties the per-architecture images together. Each of those steps has its own tool with its own flags, and every project that hand-rolls them ends up with a slightly different script.

This repository addresses that gap by being a skeleton rather than a library. The README says it is "a skeleton project for a Go application, which captures the best build techniques I have learned to date." The intended workflow is to copy the repository and edit it, not to import it as a dependency. The audience is therefore Go developers who already understand their own build requirements and want a working Makefile and Dockerfile to start from, rather than a tool that hides the steps.

The README is explicit about the environment: it has only been tested on Linux, and it depends on Docker buildx. That is a narrower claim than most build tooling makes, and it is worth taking literally. If your developers work on macOS or Windows, the template may still function through Docker, but the project does not promise it.

How the Makefile, Dockerfile.in and tools sub-module fit together

The Makefile is the entry point and the only interface a user needs to learn. It defines a small set of variables at the top, and the rest of the file is recipes that consume them. BINS lists the binary basenames to build, and the README instructs you to create one directory under cmd/ for each entry. ALL_PLATFORMS defaults to linux/amd64, linux/arm, linux/arm64, linux/ppc64le and linux/s390x. BASE_IMAGE is the FROM line of the generated Dockerfile and must be a manifest list covering every platform you keep.

Versioning is a variable with two documented strategies. The default uses git describe:

make
VERSION ?= $(shell git describe --tags --always --dirty)

The commented alternative is a manual value, shown in the Makefile as VERSION ?= 1.2.3. The README notes that the container tag is calculated from the most recent git tag and whether the repository is dirty since that tag, which is why make version exists as a target.

Dockerfile.in is a template rather than a finished Dockerfile, and the README suggests changing or removing the USER line if needed. The build itself runs through docker buildx with the current directory volume-mounted, which the README says stores incremental state for faster rebuilds. Two tools, go-licenses and golangci-lint, live in a separate tools sub-module so they can be removed along with their dependencies. Linting reads .golangci.yaml when present and otherwise falls back to golangci-lint's own defaults.

Installing the template and running a first build

There is no package to install. The README says to copy the repository and then edit it. The README lists the changes: set BINS to your binary names, replace the cmd/myapp-* directories with one directory per binary, set REGISTRY, choose a VERSION strategy, and optionally change ALL_PLATFORMS and BASE_IMAGE. It also says to change the module name in go.mod, which currently reads module github.com/thockin/go-build-template.

make
BINS ?= myapp-1 myapp-2

The defaults in the file are BINS ?= myapp-1 myapp-2 and REGISTRY ?= example.com, so both need attention before anything is pushed. With Docker buildx installed, compiling is one command. The README states that make or make build compiles the app using buildx with the current directory volume-mounted.

bash
make build

You should see the build run inside a container and produce binaries for the host platform. To cover every architecture in ALL_PLATFORMS, the README gives make all-build. Tests and linting follow the same container-based pattern:

bash
make test
make lint

Building the image is make container, and make all-container does it for all supported architectures. Publishing is make push, or make all-push for every architecture. The final step, make manifest-list, builds and pushes all containers and then publishes a manifest list joining them. Run make help to see the available targets, and make clean to remove build state.

Where the template stops helping: platform limits, credentials and release gaps

The platform restriction is the first real boundary. The Makefile comment says ALL_PLATFORMS can in theory be used for Windows platforms, but they require specific base images that the project does not have. The README repeats that the template has only been tested on Linux. A team that needs to ship a Windows binary or a Windows container image is outside the supported path, and adapting the template means writing the base image support yourself.

Registry credentials are the second. The defaults are REGISTRY_USERNAME ?= oauth2accesstoken and REGISTRY_PASSWORD ?= $$(gcloud auth print-access-token), which assume Google Cloud. Anyone pushing to a different registry must replace both, and the README does not walk through that change.

BASE_IMAGE carries a constraint that is easy to miss. The README requires it to be a manifest list with support for every platform in ALL_PLATFORMS. Adding linux/riscv64 to ALL_PLATFORMS without a matching base image will fail at image build time, not at Makefile parse time, so the error surfaces late.

The repository also publishes no releases. There is nothing to upgrade to and no version to pin, which means the template is consumed by copying and diverges immediately. Bug fixes or improvements made upstream will not reach your copy unless you diff it by hand. For a skeleton that may be acceptable, but it is a maintenance cost the README does not discuss, and there is no documented rollback or upgrade procedure.

Compared with driving the build from Go tooling instead of Make

The alternative approach is to keep the build logic in Go itself, using the toolchain's own commands and a task runner written in Go, rather than a Makefile plus a Dockerfile template. The difference is where the logic lives. With this template, the sequence of build, container, push and manifest steps is expressed as Make targets, and the container environment is defined by Dockerfile.in. With a Go-native task runner, the same sequence is expressed as Go functions, and there is no separate make dialect to learn or debug.

The trade-off is familiarity against portability. The README calls the Makefile "the universal API to software projects," which is the case for this design: any developer who has used make can read the targets, and the file is short enough to audit in one sitting. The cost is that Make is a poor language for conditional logic, and the template already shows this with its DBG_MAKEFILE switch, which uses a conditional block and a shell call to date just to change whether recipes are echoed. A Go-based runner would express the same thing in a few lines. Neither approach is wrong, but a team that dislikes Make should not adopt this template and then fight it.

Licence and the cost of keeping a copied skeleton current

The repository is licensed under Apache-2.0, and every source file in the Makefile carries the standard Apache header naming The Kubernetes Authors as the copyright holder. Copying the files into your own project means carrying that header and the licence terms with them. This is a permissive licence, but it is not a public-domain dedication, and the notice requirements still apply to the files you copy. For a definitive reading of your obligations, consult your own legal counsel; the repository text is the authority, not this summary.

The upgrade story is the weak point. Because there are no releases and no version tags to follow, the only way to take an improvement from upstream is to compare your edited copy against the current repository and merge by hand. The Makefile is the file most likely to change, since it holds the build logic, and it is also the file you will have edited most heavily. Expect the diff to be noisy. If your project depends on this template for years, budget time for that manual reconciliation, or accept that your copy is a fork in all but name.

Editorial conclusion

Adopt it if your team already lives in Make and Docker buildx and you want a multi-architecture image pipeline without writing one from scratch. Skip it if you need Windows builds, a non-Docker toolchain, or a project that ships tagged releases, because the repository has none. Before copying, verify that Docker buildx is installed on every machine that will run make, that BASE_IMAGE is a manifest list covering every entry you keep in ALL_PLATFORMS, and that your registry credentials work with the REGISTRY_USERNAME and REGISTRY_PASSWORD defaults, which assume gcloud.

Frequently asked questions

What is the go build command used in thockin/go-build-template?

The template does not call go build directly from your shell. The README states that running make or make build compiles the app through docker buildx, which mounts the current directory into a container and keeps incremental state for faster rebuilds.

How do I do a go build with thockin/go-build-template?

Copy the repository, set BINS, REGISTRY and the cmd/ directories as the README describes, then run make build. Docker buildx must be installed, and the README says the template has only been tested on Linux.

Is go get deprecated, and does that affect thockin/go-build-template?

The README does not mention go get. It states that the template assumes Go modules, which it notes are the default for all Go builds as of Go 1.13, and go.mod in the repository declares go 1.24.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. thockin/go-build-template on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/thockin-go-build-template.svg)](https://hysenlabs.com/projects/thockin-go-build-template)