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.

Directives

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 require directive still lists the module with a version
  • The replace directive 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.mod file
  • The local module's version in its go.mod does not need to match the required version

Development Workflow

  1. Make changes to shared-lib
  2. Build/test my-service — it uses the local copy automatically
  3. When satisfied, commit and tag shared-lib with a new version
  4. Update the require version in my-service
  5. Remove the replace directive 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.

Try It — go.mod Formatter

Open full tool