go2nix uses TOML lockfiles to pin module hashes. Both builder modes share
the same lockfile format, generated by go2nix generate.
# go2nix lockfile v2. Generated by go2nix. Do not edit.
[mod]
"github.com/foo/[email protected]" = "sha256-abc..."
"golang.org/x/[email protected]" = "sha256-def..."
[replace]
"github.com/foo/[email protected]" = "github.com/fork/bar"The header comment carries a format version (go2nix lockfile vN). The
current version is v2. go2nix generate always writes the current
version; older lockfiles should be regenerated.
[mod] — Module hashes. Each key is a composite "path@version" string,
each value is a sha256-... SRI NAR hash of the module as laid out by
go mod download under $GOMODCACHE (the same tree the FOD fetcher
produces).
[replace] — Module replacements (from go.mod replace directives).
Maps the original composite key to the replacement module path. Only
remote replacements are recorded; local replace directives (filesystem
paths) are not included.
Module keys use "path@version" format (e.g., "golang.org/x/[email protected]").
This keeps each module uniquely identified and avoids collisions across
versions.
The lockfile stores only module NAR hashes; the package graph is discovered
separately (eval-time plugin in default mode, build-time go list in
experimental mode — see Builder Modes).
When go2nix generate is given multiple directories, all modules are merged
into a single lockfile. Modules from different go.mod files coexist without
conflict since each is uniquely keyed by "path@version".
Regenerate the lockfile when — and only when — the module set changes:
- you add, remove, or bump a
requireline ingo.mod - a
replacedirective changes which remote module a path resolves to go.sumgains or loses entries
You do not need to regenerate after changing which packages import
which other packages, adding a new local package, or editing .go files.
The lockfile pins module hashes; the package graph is rediscovered on every
evaluation (see Package graph resolution).
go2nix generate . # rewrite go2nix.toml
go2nix check . # verify go2nix.toml still matches go.mod, no rewriteDefault mode can build without a lockfile by setting goLock = null:
goEnv.buildGoApplication {
src = ./.;
goLock = null;
pname = "my-app";
version = "0.1.0";
}When no lockfile is present, the Nix plugin is invoked
with resolveHashes = true and computes a NAR hash for each module from
go.sum + GOMODCACHE, returning a moduleHashes attrset that fills the
role of the [mod] section. Module FODs are then keyed on those hashes.
This trades a checked-in pin file for zero lockfile maintenance. The build
is still reproducible as long as go.sum is unchanged, but you lose the
explicit, reviewable hash list.
Note: the build-time staleness check (
mvscheck, see below) is skipped whengoLock = null— there is no lockfile forgo.modto drift from. Module versions are read live fromgo.sumvia the plugin on every evaluation, so ago getis reflected on the nextnix buildwith nothing to regenerate. The standalonego2nix checksubcommand still requires a lockfile path and is not applicable in this mode.
Prefer a committed lockfile for anything you ship; lockfile-free is useful for ad-hoc builds and during early development.
| When | What | Applies to | How |
|---|---|---|---|
| Generation | MVS (Minimal Version Selection) consistency | All modes | go list -json -deps resolves actual versions |
| Nix eval | Package graph | Default only | builtins.resolveGoPackages runs go list at eval time |
| Build time | Lockfile consistency | Default, with lockfile | link-binary re-reads go.mod and checks every required module is present in the lockfile at the right version; skipped when goLock = null |
In default mode, missing or mismatched modules are caught at build time when
link-binary validates the lockfile. Stale package graph information is
caught at eval time when builtins.resolveGoPackages runs go list. In
experimental mode, module mismatches surface at build time when go list or
module fetching fails inside the recursive-nix sandbox.
Run go2nix check <dir> or go2nix check --lockfile <path> <dir> to verify
a lockfile without building.