GO

GoReleaser

Release automation for Go and other projects

Developer Tools & Git ★ 16.1k stars Medium setup MIT

GoReleaser is an open-source tool that automates building, packaging, and publishing software releases. Originally for Go, it now supports many ecosystems and runs in self-hosted CI pipelines.

Key features

  • Cross-platform builds
  • Package and archive creation
  • Container image publishing
  • Changelog generation

Pros & cons

Strengths

  • One-command releases
  • Cross-compilation made easy
  • Wide packaging targets

Trade-offs

  • Some features Pro-only
  • Config grows complex

GoReleaser replaces

Last reviewed Aug 26, 2026 · 688 words

goreleaser release on a Git tag turns a Go repository into binaries for 6 or more OS and architecture pairs, deb, rpm and apk packages, checksums, a changelog and a release page with everything attached, in about a minute of CI. The catch for self-hosters is that nearly every tutorial assumes GitHub. Publishing to Gitea or Forgejo works, needs 3 lines of config and one token, and is documented in one paragraph most people never find.

Start with init and a snapshot, not a tag

go install github.com/goreleaser/goreleaser/v2@latest
goreleaser init
goreleaser release --snapshot --clean

init writes a starter .goreleaser.yaml; the snapshot flag builds everything into dist/ without needing a tag and without publishing, which is how you iterate on the config. goreleaser check validates the file. Do all of this locally before touching CI, because the feedback loop is seconds instead of a pipeline run. GoReleaser is a single Go binary, 15,997 GitHub stars, MIT licensed, and the listed 256 MB minimum is about the tool itself; the Go compiler doing the cross-builds is what actually uses memory.

Publishing to Gitea or Forgejo

Forgejo speaks Gitea's API, so the Gitea publisher covers both:

gitea_urls:
  api: https://git.example.com/api/v1/
  download: https://git.example.com

Set GITEA_TOKEN in the CI environment to a token with write access to the repository, and the release, its notes and every artifact land on your own instance. If you run Woodpecker CI beside Forgejo, the pipeline is a checkout step, goreleaser release --clean in the official goreleaser/goreleaser image, and the token as a secret. The changelog is generated from commit messages between tags, with filters for the noise, so conventional commits pay off here.

Packages and images from the same run

The same configuration adds Linux packages through the built-in nfpm integration:

nfpms:
  - formats: [deb, rpm, apk]
    maintainer: You <[email protected]>
    description: My tool

and container images through a dockers section that builds and pushes tags per architecture, with docker_manifests stitching them into one multi-arch tag. Homebrew taps, Scoop buckets, AUR packages and Nix expressions are further sections in the same file. This is the "wide packaging targets" strength and also the "config grows complex" weakness: a mature .goreleaser.yaml for a project shipping to 5 ecosystems runs to 200 lines, and each publisher has its own credentials to keep in CI. Add targets when someone asks for them, not because the option exists.

The Pro line is real but avoidable

GoReleaser Pro is a paid build with features the open-source one lacks: nightly releases, split-and-merge builds across machines, some template functions and publishing conveniences. For a project that tags releases and ships binaries plus packages, the free version is complete. You feel the line when you want to build macOS artifacts on a Mac and Linux ones elsewhere and merge them, or when you want automatic nightlies. Both have workarounds; neither is a reason to skip the tool.

No longer only Go

Recent v2 releases added builders for Rust, Zig, Bun, Deno and Python projects, so the archive, checksum, changelog and publish pipeline is available to non-Go repositories. Cross-compilation stays smoothest for Go because the Go toolchain does it natively; the other builders expect you to bring the toolchain that can target what you list. If your repository is Rust, it is a genuine option now, and better than gluing a release step together by hand in a CI pipeline.

What I'd do

Add the starter config, get --snapshot producing the binaries you want, then wire the Gitea publisher and a Woodpecker pipeline that runs on tags only. Add nfpm packages if your users install with apt; add Docker images if they run containers; stop there until asked. Keep the token scoped to one repository and rotate it when people leave. The result is a release process that is one git tag and one git push, and that reproducibility is worth more than any single packaging target.

Similar developer tools & git apps