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.
- 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
- Go Code Review Comments - Go Team