Package layout
Organize Go code by clear package boundaries, not framework-style folders.
Canonical guidance
- start simple; do not invent a deep layout before the code demands it
- split packages by cohesive responsibility, not by type of file
- use official module-era layouts as a baseline for single packages, commands, and supporting packages
- keep
internal/for implementation details not meant for external import - prefer packages that expose small, clear APIs
Use when
- starting a new service or library
- extracting subpackages
- reviewing whether a repo is over-structured
Avoid
- Java-style folder taxonomies for their own sake
models,helpers,services,managerspackages with mixed responsibilities- premature multi-package decomposition
Preferred pattern
package httpapi
import "example.com/acme/inventory/internal/store"
type Server struct {
Store *store.Store
}
Anti-pattern
/controllers
/services
/repositories
/helpers
/utils
Explanation: This anti-pattern is tempting because framework taxonomies feel organized, but they usually increase indirection without improving Go package boundaries.
Why
- Go packages are architectural boundaries
- shallow, responsibility-driven packages make imports and ownership clearer
- over-structured repos create indirection without improving design
Related pages
Sources
- Organizing Go code - Andrew Gerrand
- Organizing a Go module - Go Team
- Go Code Review Comments - Go Team
- Google Go Best Practices - Google