What is semantic import versioning, and why must v2+ modules change their import path?
The import compatibility rule says: if an old package and a new package have the same import path, the new one must be backward compatible with the old one. A major version bump breaks compatibility, so from v2 onward the major version becomes part of the module path: module github.com/acme/lib/v2, and importers write import "github.com/acme/lib/v2/client".
Because of this, v1 and v2 are different modules. They can coexist in one build, which lets a large codebase migrate step by step and avoids diamond-dependency deadlock. v0 and v1 have no suffix. v0 has no compatibility promise at all.
import (
lib "github.com/acme/lib/client" // v1.x
libv2 "github.com/acme/lib/v2/client" // v2.x, separate module
)
Gotchas: tagging v2.0.0 without changing the module line makes the go command reject the version (or treat it as +incompatible if the repo has no go.mod). Package-level state such as registries or global flags is duplicated when both majors are linked into one binary.
More on Modules, Packages & Tooling
- Q407What exactly do go.mod and go.sum contain, and is go.sum a lock file?
- Q408Explain Minimal Version Selection (MVS). How does it differ from npm/Cargo-style resolution?
- Q410How do you release v2 of a module? Compare the "major branch" and "major subdirectory" strategies, and explain +incompatible.
- Q411When would you use a replace directive, and why doesn't a dependency's replace affect your build?
- Q412Explain exclude and retract. Who writes each one, and how do they affect version selection?
- Q413What is a pseudo-version, and when does the go command generate one?