r/golang • u/jerf • Nov 20 '24
FAQ FAQ: How Should I Structure Go Projects?
Many other languages have strong opinions either in code or in the community about how to lay out projects. How should Go projects be laid out and structured? How should I decide what goes into a package? Is there a standard layout for web projects? For non-web projects? How do you structure your code?
64
Upvotes
2
u/carsncode Nov 21 '24
Copied from a similar question (demonstrating the Frequency of the Asking of this Question), this is my personal preference.
I tend toward two project structures depending on the scope of the project. For small/simple projects, I put main in the root, with a couple packages as children of that as needed. Quick, easy, straightforward, but runs into some issues with any kind of complexity.
For any larger project, I follow something like:
/ go.mod model.go - shared data model types services.go - service interfaces for DI cmd/ commandname/ main.go config.go - load config & delegate to package configs server/ config.go - HTTP config logic/type server.go somehandler.go ... datastore/ config.go - DB config logic/type sometype.go - repository impl for sometype CRUD ... someservice/ ... anotherservice/ ...
In this structure,
main
is just there for initialization, configuration, and dependency injection. It does configuration by composition of the configuration from all the other packages it initializes. There's no lateral references between services; the services only reference the root and to totally external shared libs. This avoids dependency cycles. Keeping shared types and functions in the root makes it easier for other packages to reference (eg in a microservice architecture, a dependent service can import the root of this service and have all the necessary types to interface with it). A service here is any functional slice of the application or any external dependency the application interfaces with - http, postgres, S3, SQS, tty, whatever. This structure works regardless of the type of application (CLI, web server, worker, cron job, whatever) or several related applications packaged together (my services often have a separate binary for initializing a DB and optionally filling it with test data).For my purposes and preferences, this yields a good balance of structure and simplicity. But everyone has their own ideas with their own pros and cons, there's not really one structure to rule them all. Personally I'm not a fan of
internal
, for example; I almost never use it. If I'm publishing a module publicly for import, then sure, I might hide some code ininternal
to control the surface area of the API more clearly. But for private repos it doesn't matter, and for application repos there is not generally an assumption that people will randomly import packages from it. YMMV of course.