Go packaging and releases
Read ../packaging.md, baseline.md, mise.md, and cli.md before applying these Go release specifics.
Packaging is part of the baseline when the project is meant to be installed, not an afterthought.
Choose the artifact
- Plain CLI/MCP server: cross-compiled binaries are usually enough.
- System service: add systemd/OpenRC files and consider nFPM packages.
- Desktop/Wails app: use nFPM for Linux packages, desktop files, icons, and WebKit runtime dependencies; use Wails/NSIS for Windows installers when needed.
- Library: no binary packaging unless examples/tools are part of the repo.
Version gating
Package tasks should fail on ambiguous versions. Prefer exact tags for release packages. For Git-tagged releases, a package task can gate on an exact tag:
version=$(git describe --tags --exact-match 2>/dev/null) || {
echo "Error: package builds require an exact vMAJOR.MINOR.PATCH tag" >&2
exit 1
}
version=${version#v}
For jj-backed projects, use the project's agreed jj/git-derived release command
instead. Do not infer package versions from Go BuildInfo unless the project
explicitly chose that policy. For development builds, VERSION=dev is fine; for
packages, be stricter.
nFPM baseline
# yaml-language-server: $schema=https://nfpm.goreleaser.com/static/schema.json
name: example
arch: ${GOARCH}
version: ${VERSION}
release: ${RELEASE:-1}
section: utils
priority: optional
maintainer: Amolith <amolith@secluded.site>
description: Short human description
homepage: https://example.invalid
license: LicenseRef-MutuaL-1.2
contents:
- src: build/pkg/example
dst: /usr/bin/example
For Wails/Linux desktop apps, add package assets and WebKit dependencies:
contents:
- src: build/pkg/example
dst: /usr/bin/example
- src: packaging/example.desktop
dst: /usr/share/applications/example.desktop
- src: dist/example.png
dst: /usr/share/icons/hicolor/512x512/apps/example.png
overrides:
deb:
depends:
- libwebkit2gtk-4.1-0
recommends:
- xdg-utils
rpm:
depends:
- (webkit2gtk4.1 or libwebkit2gtk-4_1-0)
apk:
depends:
- webkit2gtk-4.1
archlinux:
depends:
- webkit2gtk-4.1
mise package tasks
Use hidden preparation tasks for version, icon conversion, package build, and
optional compression. Visible tasks should be simple: pkg, pkg:deb,
pkg:rpm, pkg:apk, pkg:arch.
Minimal visible tasks look like this:
[tasks."pkg:deb"]
description = "Build a deb package"
env = { RELEASE = "1" }
run = "nfpm package -f packaging/nfpm.yaml -p deb -t build/pkg"
[tasks."pkg:rpm"]
description = "Build an rpm package"
env = { RELEASE = "1" }
run = "nfpm package -f packaging/nfpm.yaml -p rpm -t build/pkg"
UPX is optional. Use it for Linux binaries when size matters; do not assume it works well for every OS or binary format.
Cross-compilation
CGO_ENABLED=0makes plain Go binaries easy to cross-compile.- For CLI, TUI, and MCP release binaries, prefer
netgo,osusergo, optional project-specificstatic_build,-d -s -w -buildid=, and-extldflags=-staticwhen dependencies are pure Go. - Treat Go VCS build metadata as a policy choice, not the package version source.
If a package needs exact version or commit strings, derive them in the package
task and inject them. If a release intentionally relies on Go
BuildInfo, make that explicit and consider-buildvcs=true. - Wails/Linux builds require native CGO and WebKitGTK.
- Windows Wails cross-builds from Linux need mingw-w64; NSIS packages need
makensis. - macOS desktop builds require macOS unless a project has proven otherwise.
Document these constraints in task descriptions and preconditions rather than letting users discover linker failures.