| name | go-split-file |
| description | Split a large Go file into smaller files with logical groupings. Analyzes code structure and extracts cohesive units (types, functions, interfaces) into separate files within the same package. |
Go Split File
Split a large .go file into multiple smaller files, grouping related declarations logically. All files remain in the same package.
Input
User provides a .go file path. If not provided, ask for it.
Optional: user specifies desired grouping strategy or target file count. Default: auto-detect logical groupings.
Step 1: Analyze the file
Read the entire file. Identify:
- Package name — all output files share this.
- Top-level declarations — functions, types/structs, interfaces, constants, variables,
init() functions.
- Method receivers — map each method to its receiver type.
- Dependency graph — which declarations reference which others within the file.
- Logical groups — declarations that belong together (e.g., a struct + its methods + its constructor, an interface + closely related types).
- Build tags / generate directives —
//go:build, //go:generate lines at file top.
Step 2: Propose groupings
Create a split plan. Each proposed file gets:
- Filename — snake_case, derived from the primary type/function in the group. Must end in
.go.
- Contents — list of declarations moving to this file.
- Rationale — one-line explanation of why these belong together.
Grouping rules
- A struct + all its methods (by receiver) + its
New* constructor → same file. Filename: snake_case of the type name (e.g., TokenSet → token_set.go).
- An interface + closely related types that exist solely to implement it → same file (unless implementations are large enough to warrant their own files).
- Constants/variables used by only one group → move with that group.
- Constants/variables used across multiple groups → keep in a shared file (e.g.,
constants.go, types.go).
init() functions → stay in the original filename or move with the group they initialize.
- Test files: if splitting
foo.go, corresponding test declarations in foo_test.go should be split to match (e.g., bar.go gets bar_test.go). Ask user before splitting test files.
- Target ~500–1000 lines per resulting file (same sizing as
go-package-reorg). Avoid files under ~50 lines unless they own a single cohesive concept.
- Preserve doc comments — they move with the declaration they document.
- Build tags and generate directives: only include in files that need them.
Step 3: Present plan and get approval
Show the user a table:
| New file | Declarations | Lines (approx) | Rationale |
|---|
Ask: "Proceed with this split? You can adjust groupings before I start."
NEVER proceed without user approval.
Step 4: Execute the split
For each new file in the plan:
- Write the
package declaration.
- Copy the relevant declarations in their original order.
- Preserve all comments, doc strings, and blank-line spacing from the original.
- Do NOT manually write import blocks —
goimports handles this in Step 5.
After all new files are created:
- Remove extracted declarations from the original file.
- If the original file is now empty (or contains only the package declaration), delete it.
Step 5: Verify
- Run
goimports -w on all new/modified .go files in the package directory.
- Run
go build ./... from the module root to confirm compilation.
- Run
go vet ./... to catch issues.
- Run package tests:
go test ./<pkg>/... -count=1 — splits can move test declarations.
If verification fails, diagnose and fix. Common issues:
- Circular dependencies → cannot happen within same package, but check for build tag issues.
- Unexported symbols referenced across files → fine in Go (same package), no action needed.
- Duplicate declarations → a declaration was copied but not removed from the original.
Step 6: Report
Show the user:
- List of files created/modified/deleted.
- Line counts before and after.
- Any manual follow-up needed (e.g., updating documentation, build configs).