- 100+ Go versions — from 1.17 to latest, including release candidates, updated within 4 hours of a new release on go.dev.
- No stale
vendorHash — dependencies are pinned per-module with NAR hashes. Change a dep, re-run govendor. No hash archaeology.
- Workspace support — build multi-module
go.work monorepos reproducibly. Neither buildGoModule nor gomod2nix can do this.
- Go tools pinned to your toolchain — govulncheck, gopls, golangci-lint, and more, updated within 6 hours of release and version-locked to your selected Go version with a clear error if incompatible.
- Private modules — standard Go authentication via
.netrc, no custom infrastructure required.
Getting Started
Try Go without installing anything
nix run github:purpleclay/go-overlay -- version
# go version go1.26.2 linux/amd64
Create a new project
The template bootstraps a new project with a dev shell, builder, and drift detection pre-configured:
nix flake new -t github:purpleclay/go-overlay my-app
cd my-app && nix develop
Create a workspace project
The workspace template bootstraps a minimal multi-module monorepo with a dev shell, builder, and drift detection pre-configured:
nix flake new -t github:purpleclay/go-overlay#workspace my-monorepo
cd my-monorepo && nix develop
Onboard an existing project
Add go-overlay to your flake.nix inputs and apply the overlay:
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
go-overlay.url = "github:purpleclay/go-overlay";
};
outputs = { nixpkgs, flake-utils, go-overlay, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ go-overlay.overlays.default ];
};
in { ... }
);
}
[!TIP]
Not using flakes? See the traditional Nix installation guide.
2. Add govendor to your dev shell
govendor generates and maintains the dependency manifest used during builds:
devShells.default = pkgs.mkShell {
buildInputs = [
go-overlay.packages.${system}.govendor
];
};
3. Generate and commit the manifest
govendor
This creates a govendor.toml with NAR hashes for all dependencies. Commit it to your repository.
[!IMPORTANT]
Re-run govendor whenever you add, remove, or upgrade a dependency. Use govendor --check in CI to catch drift before it reaches production.
4. Build
Create a default.nix file to define your package:
{ pkgs, go }:
pkgs.buildGoApplication {
inherit go;
pname = "my-app";
version = "0.1.0";
src = ./.;
modules = ./govendor.toml;
}
Then wire it into your flake.nix outputs:
let
go = pkgs.go-bin.fromGoMod ./go.mod;
in {
packages.default = pkgs.callPackage ./default.nix { inherit go; };
}
[!TIP]
fromGoMod auto-selects the Go version from your go.mod. For other version selection options, see the reference guide.
And then build it:
nix build
That's it. No stale vendorHash to fix after every dependency change. 👋
Examples
Not sure how to configure a specific feature? Each example is a self-contained, buildable project — find the pattern you need and use it as a starting point.
| Example |
Features |
| hello-world |
stdlib-only, no manifest |
| http-chi-server |
External deps, modules |
| cobra-cli |
ldflags, subPackages, doCheck, version injection |
| cross-compile |
GOOS, GOARCH, CGO_ENABLED |
| build-tags |
tags parameter |
| local-replaces |
Local replace directives, localReplaces |
| oapi-codegen |
tool directive, preBuild code generation |
| sqlc-codegen |
nativeBuildInputs, preBuild code generation |
| vendored |
Committed vendor/ directory |
| go-workspace |
buildGoWorkspace, go.work, subPackages |
| go-workspace-inferred |
buildGoWorkspace, inferred go.work |
| go-workspace-vendored |
buildGoWorkspace, committed vendor/ |
| wasm-build |
mkVendorEnv + stdenv.mkDerivation |
| nixpkgs-build-go-module |
buildGoModule.override with go-overlay toolchain |
Build or run any example directly:
# pattern: nix build .#example-<name>
nix build .#example-cobra-cli
nix run .#example-cobra-cli
Every Go toolchain derivation includes version-locked tools — gopls, golangci-lint, govulncheck, delve, and more — pinned to your selected Go version and updated within 6 hours of a new release.
Add them all to your dev shell with a single attribute:
let
go = pkgs.go-bin.fromGoMod ./go.mod;
in {
devShells.default = pkgs.mkShell {
buildInputs = [
go.withDefaultTools
];
};
}
For selecting specific tools or pinning versions, see the Go Tools reference.
Detecting Drift with Git Hooks
Use cachix/git-hooks.nix to check for manifest drift on commit:
let
pre-commit-check = git-hooks.lib.${system}.run {
src = ./.;
hooks.govendor = {
enable = true;
name = "govendor";
entry = "${go-overlay.packages.${system}.govendor}/bin/govendor --check";
files = "(^|/)go\\.(mod|work)$";
pass_filenames = true;
};
};
in {
devShells.default = pkgs.mkShell {
inherit (pre-commit-check) shellHook;
buildInputs = pre-commit-check.enabledPackages;
};
}
Private Go Modules
Private modules require two things: bypassing the public proxy, and credentials to authenticate with the private host. Set GOPRIVATE to route around the proxy and netrcFile to provide credentials:
[!TIP]
GOPRIVATE implicitly sets GONOPROXY and GONOSUMDB — you only need to set all three explicitly if you require different values for each.
{ pkgs, go }:
pkgs.buildGoApplication {
inherit go;
pname = "myapp";
version = "1.0.0";
src = ./.;
modules = ./govendor.toml;
netrcFile = "${builtins.getEnv "HOME"}/.netrc";
GOPRIVATE = "<your-private-host>/*";
}
[!NOTE]
builtins.getEnv "HOME" reads the host environment to locate ~/.netrc — this is why --impure is required. The file contents are read at eval time and passed into the build sandbox. Credentials are not stored in the repo. If you prefer to keep a .netrc inside the source root, consider encrypting it with git-crypt or sops-nix.
nix build --impure
[!CAUTION]
The .netrc contents are embedded in the derivation, which is stored in the Nix store. The Nix store is world-readable by default.
Further Reading
- reference.md — Full option tables for all builder functions, library functions, and traditional Nix installation.
- govendor-toml-v2.md —
govendor.toml schema reference.
- migrating.md — Migration guides from gomod2nix and buildGoModule.
The go-overlay logo was generated using Google Gemini. The Go gopher was originally designed by Renee French and is licensed under CC BY 4.0. The Nix snowflake is a trademark of the NixOS Foundation. This project is not affiliated with the Go project, the NixOS Foundation, or Google.