How do you work with private modules?

5 minadvancedgomodulesprivate-modulesgoprivate

Quick Answer

GOPRIVATE (a comma-separated list of glob patterns, e.g. GOPRIVATE=github.com/mycompany/*) tells the go command which module paths are private, so it skips both the public module proxy and the checksum database for anything matching, and fetches those modules directly from their source (typically a private Git host) using your local Git credentials instead. You'll also usually need Git itself configured to authenticate against the private host, often via git config --global url."https://<token>@github.com/".insteadOf "https://github.com/" in CI, or SSH keys for interactive development. GONOSUMCHECK/GOFLAGS and GOPROXY can be tuned similarly, but GOPRIVATE alone is usually sufficient, since it implicitly adjusts both GONOSUMCHECK and GOPROXY behavior for matching paths.

Detailed Answer

Private modules need to bypass two things. The public proxy can't reach a private repo anyway. The public checksum database has no legitimate way to know about code that was never published publicly.

Setting GOPRIVATE

export GOPRIVATE=github.com/mycompany/*,gitlab.internal.corp/*

Any module import path matching one of these glob patterns skips proxy.golang.org and sum.golang.org entirely, going straight to the source host instead.

Configuring Git authentication for CI

git config --global url."https://${GH_TOKEN}@github.com/".insteadOf "https://github.com/"

This rewrites any https://github.com/... URL Go tries to fetch into an authenticated URL using a personal access token or CI-provisioned token, which is the standard way to let go mod download succeed against a private GitHub repository in a CI pipeline.

SSH-based authentication for local development

# ~/.gitconfig
[url "git@github.com:"]
    insteadOf = https://github.com/

This rewrites HTTPS GitHub URLs to SSH, letting Go fetch private modules using your existing SSH key setup, which is common for individual developers who already have SSH access configured for their private repos.

A common gotcha: forgetting GOPRIVATE entirely

This error is easy to misread as a version problem, when it's really an authentication problem:

go: github.com/mycompany/internal-lib@v1.0.0: reading github.com/mycompany/internal-lib/go.mod at revision v1.0.0: unknown revision v1.0.0

Without GOPRIVATE set correctly, go tries the public proxy first, which naturally has no access to a private repository, and the resulting error message is often confusing since it doesn't clearly say "this is a private-module authentication problem."

The practical checklist

Set GOPRIVATE for every private module path pattern your project needs, configure Git credential rewriting appropriately for both local development and CI, and verify with go mod download in a clean environment (or CI) before assuming it's fully working.