Local Module Development with Replace Directives
Set up local module development in Go using replace directives to point dependencies to local paths. Learn the workflow for developing multiple modules simultaneously.
Detailed Explanation
Local Module Development
When developing multiple Go modules simultaneously, replace directives with local paths enable you to test changes without publishing to a registry.
The Basic Setup
If you have two modules:
~/projects/
├── my-service/ # Main application
│ └── go.mod
└── shared-lib/ # Shared library
└── go.mod
In my-service/go.mod:
module github.com/myorg/my-service
go 1.22.0
require github.com/myorg/shared-lib v1.2.0
replace github.com/myorg/shared-lib => ../shared-lib
How Local Replaces Work
- The
requiredirective still lists the module with a version - The
replacedirective redirects to the local file system path - Local paths must be relative (starting with
./or../) or absolute - The local module must have a valid
go.modfile - The local module's version in its go.mod does not need to match the required version
Development Workflow
- Make changes to
shared-lib - Build/test
my-service— it uses the local copy automatically - When satisfied, commit and tag
shared-libwith a new version - Update the
requireversion inmy-service - Remove the
replacedirective before committing
Common Mistakes
Forgetting to remove replace before commit:
// DON'T commit this!
replace github.com/myorg/shared-lib => ../shared-lib
CI will fail because the relative path does not exist on the build server.
Wrong relative path: The path is relative to the module root (where go.mod lives), not the current working directory.
CI Protection
Add a CI check that fails if local replace directives exist:
if grep -q '=>.*\.\./' go.mod; then
echo "ERROR: Local replace directives found in go.mod"
exit 1
fi
Alternative: Go Workspaces
For Go 1.18+, consider using go.work files instead of replace directives for local development. Workspaces are designed for multi-module development and do not require modifying go.mod.
Use Case
Local module development is a daily workflow for teams maintaining multiple Go modules. Backend teams often have shared libraries for logging, authentication, or database access. Using replace directives allows testing changes across module boundaries before publishing. The formatter helps keep go.mod clean when toggling between local and published dependencies.