| name | migrate-go-package |
| description | Migrate Go APIs and their implementations from one package to another while preserving existing callers with //go:fix inline compatibility declarations. Use when asked to move, relocate, split, or rename a Go package without changing call sites all at once. |
Migrate Go Code Between Packages
Move an API into a destination package in stages, use //go:fix inline compatibility declarations in the source package, rewrite callers with go fix -inline, and remove the source declarations only after no callers remain.
Follow the repository's instructions for branches, generated files, formatting, testing, and package documentation throughout the migration.
Preconditions
- Require Go 1.26 or newer and confirm the inline fixer is available with
go tool fix help inline.
- Identify the source package, destination package, migration scope, and applicable build configurations.
- Determine whether consumers exist outside the repository. Do not delete a published compatibility package unless all consumers are in scope or the user has approved a breaking change.
- Start from a clean worktree before applying
go fix. Do not overwrite unrelated user changes.
- Run the repository's normal compile and test commands to establish a baseline. If none are documented, use
go test ./... and go build ./....
Supported Compatibility Declarations
Place //go:fix inline directly above every supported declaration that remains temporarily in the source package.
Types
Move the type definition, its methods, and supporting implementation to the destination package. Replace the source definition with an alias:
type Original = newpkg.Original
The source package cannot define methods on the alias. Move all methods first. Also move source-package code and same-package tests that rely on the type's unexported fields.
Constants
Move the named constant to the destination package, then forward it from the source package:
const SomeConst = newpkg.SomeConst
The forwarded value must refer to another named constant. Prefer standalone declarations so each directive is unambiguous.
Functions
Move the implementation to the destination package. Keep a forwarding function declaration with the same signature in the source package:
func SomePkgFunc(value string) error {
return newpkg.SomePkgFunc(value)
}
Preserve parameter order, variadic expansion, results, and behavior exactly. For functions without results, call the destination function without return.
Do not replace a function declaration with a function-valued variable:
var SomePkgFunc = newpkg.SomePkgFunc
The inline fixer does not rewrite variable references, and changing a function declaration into an assignable variable changes the API.
Variables
//go:fix inline does not migrate package variables. Copying a variable into the source package creates separate state rather than forwarding reads and writes.
Treat every exported source-package variable as a blocker. Manually migrate all references to the destination variable, redesign the API, or retain the source compatibility package. Do not delete the source declaration until the chosen approach preserves its semantics.
Workflow
1. Inventory the migration
Create an explicit inventory of:
- Exported types, aliases, constants, variables, functions, and methods to move
- Unexported helpers, state, and initialization code required by those declarations
- Tests, examples, generated sources, package documentation, and repository ownership metadata
- Importers under all relevant build tags, operating systems, and architectures
Identify import-cycle risks before editing. The destination package must not import the source package after the move.
Search for non-call function references such as callbacks or assignments (handler := oldpkg.Handle). go fix -inline rewrites calls, not uses of a function as a value.
2. Duplicate the implementation in the destination
Add every exported declaration in scope and all implementation it needs to the destination package. Move methods with their receiver type. Move mutable state and initialization exactly once; do not leave duplicate registrations or side effects in both packages.
Copy or adapt tests to exercise the destination implementation directly. Preserve the source implementation until the destination compiles and its tests pass.
Do not edit generated files directly. Update their source or generator and regenerate them using repository instructions.
3. Replace source implementations with compatibility declarations
After the destination works:
- Replace moved types with aliases to the destination types.
- Replace moved constants with named constants assigned from the destination.
- Replace moved functions with forwarding function declarations.
- Add
//go:fix inline directly above each supported compatibility declaration.
- Remove old methods and implementation helpers once the source compatibility layer no longer uses them.
Do not add directives to ordinary variables or function-valued variables. Record and resolve those references manually.
4. Validate the compatibility layer
Format changed files using the repository's formatter, then run the repository's compile and test commands. If none are documented, use go test ./... and go build ./.... Fix all failures before rewriting callers.
Pay particular attention to:
- Source-package code that accessed fields or identifiers now unexported in the destination
- Import cycles
- Duplicate
init behavior or mutable state
- Signature, generic constraint, and variadic mismatches
- Build-tagged or platform-specific files
5. Preview and apply caller rewrites
Preview only inline fixes:
go fix -inline -diff ./...
Review the diff before applying it. The source-level inliner preserves evaluation order and other semantics, but its output may need stylistic cleanup.
Expect the preview command to exit nonzero when it finds a diff.
Apply the rewrites:
go fix -inline ./...
Run the command again if the first pass exposes additional inline opportunities. For repositories with multiple supported build configurations, repeat with the relevant -tags, GOOS, and GOARCH values.
Format every changed Go file according to repository instructions.
6. Find and resolve remaining callers
Search for the exact source import path, not only the package identifier, because callers may rename imports. Also inspect generated inputs and build-tagged files.
Remaining references commonly include:
- Package variables, which the inline fixer cannot rewrite
- Functions used as values rather than called
- Unsafe inlinings the analyzer declined
- Files excluded by the analyzed build configuration
- Generated files whose source or generator must change
- Consumers outside the repository
Do not delete the source package while any in-scope reference remains.
7. Validate after caller migration
Run the repository's compile and test commands again, falling back to go test ./... and go build ./... when needed. Confirm that in-scope packages no longer import or depend on the source package.
8. Delete the source compatibility layer
Only after the source package has no in-scope consumers:
- Delete the compatibility declarations and any now-empty source package.
- Remove obsolete tests, package documentation, ownership entries, and generated configuration.
- Format changed files and run the full required compile and test commands one final time.
If external consumers remain, stop after the compatibility layer and report why deletion is unsafe.
Failure Handling
- Import cycle: Move or extract the shared dependency; never make the destination import the source.
- Exported package variable: Stop automatic migration for that name and choose a manual or redesigned migration.
- Function used as a value: Rewrite that reference manually to the destination function.
- Inline fix not offered: Check directive placement, confirm the declaration is a supported type alias, named constant, or function declaration, and inspect whether the rewrite would be unsafe.
- Remaining imports after
go fix: Check build tags, platforms, generated sources, package variables, function values, tests, tools, and examples.
- External consumers: Retain the compatibility package unless a breaking change is explicitly approved.
Completion Report
Report:
- Declarations and implementation moved
- Temporary compatibility declarations added
- Callers rewritten automatically and manually
- Any compatibility package retained and why
- Final source-package deletion status
See references/go-inline-migration.md for declaration rules and command details, and examples/basic-usage.md for a complete migration example.