The Multi-Module Problem
In large organizations, a monorepo often contains multiple Go modules that depend on each other:
repo/
├── pkg/
│ └── auth/
│ └── go.mod (module: github.com/myorg/auth)
└── services/
└── login/
└── go.mod (module: github.com/myorg/login, requires: github.com/myorg/auth v1.2.0)
The problem: you are adding a new function to auth. You want to test it immediately in login before pushing and tagging a new release. Historically, the only way to do this was a replace directive in login/go.mod:
// go.mod (BEFORE workspaces — the old, painful way)
module github.com/myorg/login
require github.com/myorg/auth v1.2.0
replace github.com/myorg/auth => ../../pkg/auth // ← MUST remove before git push
This worked, but it was error-prone. Engineers would forget to remove the replace directive before pushing, breaking the CI pipeline. Or they would remove it and forget to add it back, losing their local changes. It was a constant source of friction.
The Solution: go.work
Go 1.18 introduced Workspaces. You create a single go.work file at the repository root, initialized against the module directories it should span, which generates:
// go.work
go 1.21
use (
./pkg/auth
./services/login
)
Now, when you run go build or go test inside services/login, the Go toolchain automatically uses your local ./pkg/auth source — no replace directives needed, and no changes to any go.mod file. The go.work file is typically added to .gitignore so each developer can configure their own workspace without affecting others.
You can also add a replace directive at the workspace level (in go.work, not go.mod) to override a dependency for the entire workspace, the same way go.mod's own replace directive works but scoped to every module in the workspace at once rather than just one.
A GOWORK=off environment variable is particularly important for CI pipelines. Your CI system should build against the published module versions (what is in go.mod), not your local workspace overrides. Setting it in CI ensures the workspace file is ignored even if it was accidentally committed.