Golang Project Layout
Go is an opinionated language but when it comes to project structure you are on your own! It was pretty confusing to me but all you need is a structure that works and that you can repeat. I’m going to show you what I do — you might like doing things a different way and that’s cool. There’s a bunch of ways to structure a Go project but this works for me and I’ve built plenty of things with it :)
Layout
Here is the root
layout for a personal project I’m working on:
/.github/workflows
I’m happy to share the code from these workflows if anyone is interested. The three of these files ensure that my PRs automatically run tests and that merges to main
will be dockerized and pushed to my container registry. I manually deploy my changes for now so that’s all these do.
/api
I’m redacting some stuff so sorry about that. The point should be clear though. This file is for the api
. This is an http API so all my endpoints are defined in this folder. This folder makes use of the code from the other folders to serve responses. You’ll see I define my middlewares here — think structured logging, tracing, metrics.
/cmd/server
This is where the start-up code for the application goes. This is the main
method for the service. All the routes, logic and server startup code goes in the server.go
file. I also combine my middlewares with my routes here. If you’d like to see what these files actually look like I’m happy to share that in another post. I wanted this one to focus on the layout of a project more than the specifics of how I implement things. Let me know!
/decks
The decks directory is for a model/data that I plan to store and retrieve from postgres. This directory holds the database model deck.go
and the repository and tests for it ( container_test.go
is used for tests). Tests are run against docker using a library called testcontainers
. You can see an example of how this works in my previous post
/groups
This directory is very similar to /decks
. What can I say, I’m a sucker for simple and easily-repeatable patterns for development. This folder covers the concept of groups for my project. You’ll see two repos and while that may seem like I’m mixing concepts between folders and groups I assure you I am fine with this setup and it works. This is all postgres and again I’m testing against a docker container — tests take like 3 seconds so while it’s slower than simple unit tests it’s nearly as fast and faster than your typical “integration test”.
/mocks
This folder is generated by https://github.com/vektra/mockery — it takes interfaces
from your project and automatically generates some mocks that you can use for your tests. I know some people will want to vom looking at this but /shrug. This makes testing easy and straightforward for me. If you’re interested in understanding how I use mockery let me know, I’ll probably make a post about it cuz it was a nice productivity increase.
/pkg/tools
This module has a few helpers that allow me to test some more side-effecty kinds of things. In my tests it helps to control the time and uuids being generated so this package creates an interface and implementation that I can use everywhere and mock out in tests. Some people say you shouldn’t have a utils
or tools
module but it never made sense to me so I have one.
/seed
This contains some sql scripts for local testing :)
/users
Looks familiar huh? This programming thing ain’t so hard afterall… okay yeah so the service you’re looking at doesn’t have the most complex code, but I assure you this structure extends well beyond simple projects. This is another repository for storing and retrieving users.
FIN
You’ll notice a lack of service logic in this project. I haven’t found a need to separate business logic at this point so there are no specific files for that. I have used this structure for production services and personal projects. It’s versatile and it’s simple. It’s repeatable for basically any project and avoids most common pitfalls (think cyclic dependencies). But hey, don’t just trust me. Try it out - fuck wid it and make it your own.