Module Release Workflow
Purpose and Scope
This page explains a practical release workflow for a Go module: choose the next version, verify the module from a caller’s point of view, publish the version in source control, update dependent code, and confirm that the released module works with the public Go toolchain. A module is the unit of dependency management in Go. It is identified by a module path, records requirements in module metadata, and is consumed by other modules through imports and version selections. The official module release workflow emphasizes reliability for downstream users, not just tagging code when it happens to compile.
For a public module, the release is part of Go’s decentralized publishing model. The Go project’s repository README frames Go itself as open source software with a canonical Git repository, a GitHub mirror, official binary distributions, source installation instructions, and contribution guidance. That matters because module authors publish into the same ecosystem of source repositories, tags, and released toolchains. A well-run module release should be reproducible with an official Go installation and understandable to developers who clone, inspect, build, and test the source. Sources: README.md
The workflow below follows the official Go documentation sequence: begin and organize a module, test it locally from a separate caller module before it is published, use v0 pre-releases when the API is still experimental, publish versions with meaningful semantic version numbers, and continue patch or minor releases as the module evolves. The repository files listed here do not implement that whole module workflow directly; instead, they show the distribution and command entry points that a release depends on when users build, test, profile, assemble, cgo-build, or cross-test code after consuming a module.
Relevant Source Files
README.md— Establishes the Go repository as the source for the open source Go programming language, points to official binary distributions and source installation instructions, and links contribution guidance. This anchors the release workflow in the public Go distribution used by module consumers.misc/go_android_exec/main.go— Provides the Android execution wrapper used by the Go tool during Android testing. It is relevant to release verification because modules with mobile or cross-platform behavior should be tested in the same kind of target-specific execution environment that the Go project itself supports.src/cmd/addr2line/main.go— Implements thego tool addr2linehelper used by pprof-style symbolization. It illustrates that released modules may be diagnosed with bundled Go tools, and that tool interfaces can be intentionally narrow or internal to a workflow.src/cmd/asm/main.go— Implements the Go assembler command entry point. It matters for modules that include assembly files or depend on architecture-specific code, because release verification must include the target architectures and build flags those files require.src/cmd/cgo/main.go— Defines core cgo package and file structures, showing how cgo collects Go files, C references, preambles, linker flags, and exported functions. It is important for modules that expose or consume C interoperation.src/cmd/compile/internal/gc/main.go— Describes the compiler main pipeline as parsing flags and Go source files, type-checking a package, compiling functions to machine code, and writing package output. This grounds the final release check in the actual compiler phases that every module build must pass.
Workflow Overview
Start by deciding what kind of release you are making. A first public version is often a v0 release, which communicates that the API is available for users to try but is not yet stable. Later v0 versions may contain fixes, additions, or breaking changes. Once the module promises stability, version numbers become part of the user contract: patch releases should fix defects without changing public API expectations, minor releases may add compatible functionality, and major releases communicate incompatible changes through Go’s semantic import versioning conventions.
Before publishing, verify the module as a consumer would use it. The official tutorial pattern is to create a separate caller module, initialize it with go mod init, import the package by its module path, and run application code that calls exported functions. This separate-client test is important because a module can appear correct inside its own directory while still failing for users because of import paths, package names, missing exported identifiers, incomplete examples, or dependency metadata that only matters from outside the module.
A minimal local verification loop looks like this:
mkdir hello
cd hello
go mod init example.com/hello
# write code that imports your module path
go test ./...
go run .When the module is not yet published, use the local-development mechanism described by the module documentation so the caller can resolve the unpublished source. The goal is not to bypass versioning forever; it is to catch problems before a tag is visible to everyone. After the local caller succeeds, run the module’s own tests, examples, and platform-specific checks. If the module uses cgo, assembly, or unusual targets, include those paths in the release checklist instead of treating go test ./... on one workstation as the whole signal.
System-to-Code Mapping
The repository README is the release workflow’s distribution anchor. It distinguishes the canonical source repository from the GitHub mirror, points readers to official downloads, explains source installation when a binary is unavailable, and sends contributors to Go’s contribution process. For module authors, the lesson is that consumers will build with a concrete Go distribution and expect source repositories, tags, documentation, and issue workflows to line up. A module release should therefore specify the intended Go version range, keep its repository metadata clear, and document how users should report issues. Sources: README.md
The compiler entry point shows why a release cannot be defined only by repository tags. src/cmd/compile/internal/gc/main.go describes the compiler main function as the process that parses flags and Go source files, type-checks the parsed package, compiles functions to machine code, and writes the compiled package definition. If a module’s public package graph does not pass these phases under the supported Go versions, the tag is not a usable release. This is especially relevant when a release changes generic APIs, build tags, unsafe code, or generated files. Sources: src/cmd/compile/internal/gc/main.go
The cgo entry point maps release verification to packages that cross the Go/C boundary. src/cmd/cgo/main.go defines a package-level collection of Go files, gcc output files, C preambles, linker flags, C references, calls, exported functions, and directives such as no-callback and no-escape metadata. A module release that depends on cgo should test not only Go compilation but also the C compiler environment, linker flags, exported symbols, and target operating systems that users are expected to support. Sources: src/cmd/cgo/main.go
The assembler entry point maps release verification to architecture-aware source. src/cmd/asm/main.go checks the build configuration, selects an architecture, parses assembler flags, initializes object-linking context, defines GOEXPERIMENT macros for eligible assembly, parses input files, and writes object files. If a module includes .s files or relies on assembly selected by build tags, a release should test the relevant GOARCH values and any custom assembler flags. A tag that works only on the maintainer’s architecture may fail immediately for users on another supported platform. Sources: src/cmd/asm/main.go
The Android execution wrapper demonstrates that target-specific release checks sometimes require more than cross-compilation. misc/go_android_exec/main.go is designed to be used by the Go tool as go_android_GOARCH_exec, serializes flaky adb access with a file lock, waits for a booted device, copies a GOROOT, prepares temporary device paths, and runs binaries on Android. Module maintainers do not need this exact wrapper for ordinary releases, but the file shows the kind of environment-specific harness needed when a module claims Android runtime support. Sources: misc/go_android_exec/main.go
The addr2line tool shows how diagnostics fit into release verification. src/cmd/addr2line/main.go implements a minimal go tool addr2line interface for pprof, reading hexadecimal program counters from standard input and printing function names and file-line locations. Released modules that affect performance, crash analysis, or production debugging should preserve symbolization quality by building with normal toolchain expectations and by keeping generated or assembly code debuggable enough for Go’s bundled diagnostic tools. Sources: src/cmd/addr2line/main.go
Release Verification Checklist
Use a checklist that separates source readiness from consumer readiness. Source readiness means the module is organized, formatted, documented, tested, and tagged consistently. Consumer readiness means a different module can require it, import it, build it, run tests, and diagnose failures using the Go distribution. Keep these concerns distinct because many release mistakes appear only when dependency resolution, import paths, build constraints, or generated artifacts are exercised from outside the repository.
A compact release sequence is: choose the next version, update documentation and examples, run formatting and tests, test from a separate caller module, verify special build paths, tag the repository, then update one real dependent module to the new version. For an experimental release, use v0 pre-release or v0 versioning to set expectations. For a stable module, make sure the version number matches the compatibility promise. For a breaking stable change, plan the major-version module path before tagging so consumers get a coherent import path and version story.
# inside the module repository
go test ./...
# from a separate consumer module
go mod init example.com/release-check
go get example.com/your/module@vX.Y.Z
go test ./...Do not skip platform and toolchain checks that match your module’s implementation. A pure-Go library may only need supported Go versions and operating systems. A cgo module needs C compiler and linker checks. An assembly-heavy module needs architecture coverage. A module advertised for Android needs runtime execution checks, not just compilation. A performance-sensitive module should leave enough information for profiling and symbolization. These checks connect the public module contract to the actual commands and tools shipped in the Go repository.
Practical Next Steps
If you are preparing a first release, start with a small v0 version and verify it through a separate caller before announcing it. If you are maintaining an existing module, write down the compatibility expectation for each release type, keep release notes close to the code change, and test the tagged version exactly as users will request it. When a release introduces cgo, assembly, new platform support, or compiler-sensitive language features, expand the checklist before publishing rather than after users report failures.
Related pages: modules-overview, go-mod-reference, managing-dependencies, module-versioning, publishing-modules, go-command, testing, cgo, assembly-guide.