How I structure Go applications
Now the Go team has guidance on this: https://go.dev/doc/modules/layout
A topic that allows for many options and ways of doing it is how to structure a project. In this case I want to share an approach I am following for private Go applications that suits me well, using flavors of Domain-driven design and Clean Architecture, to make it easy to see what the application is about, where to place different pieces, and to be highly adaptable to changing requirements.
Directly to the point, the structure for an application that handles products would be:
.
└── /product-app
├── /http
│ ├── handler.go
│ ├── handler_test.go
│ └── server.go
├── /product
│ ├── types.go
│ ├── errors.go
│ ├── product.go
│ └── product_test.go
├── /storage
│ ├── driver.go
│ └── store.go
└── main.go
Files are named for what they contain in a generic way, making it easier to see what the file provides. Packages are named for what they are, divided by domain.
Using the layers of the Clean Architecture as inspiration, we split the application into two layers.
One is the inner layer, composed by the folder product
which represents the core domain and contains the entities that represent a product, the errors that could exist, and the business logic or actions of the application. This layer does not depend nor is affected by changes in the outer layer, and provides the signatures to be used via interfaces by the outer layer via dependency injection.
The other is the outer layer, where we have the folders http
and storage
, which contain the code that connects the application with external components. This layer is the most likely to change, so it has no dependent parts and contains all framework-specific code. Subpackages can be added for each specific implementation, for example grpc
or rest
for http, and redis
or postgres
for storage.
In the root folder, we have the main.go
file, used to set up all the wiring needed to run the app and to provide a starting point for the binary. In case of multiple binaries, like an API and a CLI for example, a folder named cmd
could be created, containing a main.go
for each way to run the app. Any configuration or third-party files would live in the root folder too, or in separate folders if needed.
When there are too many files and packages in the root package, a grouping can be done into an internal
folder to store all the Go code.
Anyways, the important part is to keep the layers separated and respect the dependencies flow. In case of doubt, keep it simple and add structure as needed.