Layered architecture organizes packages so dependencies flow in one direction: higher, more specialized packages may import lower, more general packages, but lower packages never import upward. The arrangement is a practical model rather than a literal package hierarchy; Go packages remain independent and flat. section 8.1.1 section 8.1.2
Its immediate purpose is to prevent import cycles. If package A imports B and B imports A, Go reports a compile-time error. Keeping foundational functionality below specialized delivery or application code makes dependencies explicit and makes the codebase easier to follow. section 8.1.1 section 8.1.2
Build layers around focused package responsibilities:
- Put reusable, domain-level services in lower packages that do not depend on delivery mechanisms. section 8.1.2
- Place adapters such as REST APIs above the core packages they expose. section 8.1.2
- Keep executable commands at the edge, where they wire packages together to run an application. section 8.1.2
- Treat each package as an expert provider of a specific capability; avoid catch-all names such as common, util, shared, or helper. section 8.1.1
Core service, REST API, and command
A link-management package can hold core services. A link/rest package can import that package to provide an HTTP REST API, while a linkd command wires both into a server. A separate CLI can use the core package directly, bypassing the REST layer; an HTTP-client CLI can instead call the server. These alternatives work because upper layers depend downward rather than forcing the core package to know its consumers. section 8.1.2
Layering is a guide, not a reason to introduce abstractions early. Start simply, split packages when the project needs it, and preserve clear dependency direction as services, APIs, and commands grow. section 8.1.1 section 8.10
Figure 8.4 A layered approach to organizing packages
This diagram maps a layered package arrangement in which imports move from specialized packages toward foundational ones. section 8.1.2






