Getting Started with Go: Project Structure

Mike Dyne
Evendyne
Published in
4 min readFeb 25, 2023

When it comes to structuring a Go project, it can be challenging to determine the best practices and patterns to follow. A good project structure helps to organize your code in a logical and maintainable way. It also makes it more modular, easier to test and easier for other developers to understand the codebase and contribute to the project.

Project structure in Visual Studio Code. The additional env files can be useful for testing, CI or simple templating purposes.

There are several industry-standard Go project layouts like Standard Go Project Layout or Go Clean Template, each with its own unique set of advantages and recommended patterns. However, depending on your project’s architecture and specific requirements, you may need to create your own variation. In this article, I will present my own variation of a Go project layout that has proven to be successful in my projects over the years.

Project Structure

When designing this project structure, I prioritized several important principles to ensure the code is sensible and easily maintainable. Let’s explore these principles in detail.

Clear separation of concerns: The project is organized into directories with specific responsibilities, making it easy to understand the structure.

Encapsulation of internal packages: Internal packages are encapsulated inside the internal directory, preventing other projects from importing them and reducing coupling between packages.

Modularity and reusability: The packages in the pkg directory can be imported and used by other Go projects, promoting modularity and reusability.

Flexibility in deployment: The deployment directory contains deployment files for different environments, making it easy to deploy the application in different contexts.

Layered architecture: The project follows a layered architecture pattern, with the api layer handling HTTP requests, the service layer implementing the business logic, and the repository layer interacting with the data storage.

Dependency injection: The packages in the api and service layers depend on the packages in the repository layer, which are injected at runtime using interfaces.

Go modules: The project of course uses Go modules to manage its dependencies, making it easy to version and manage them.

mywebapp/
├── cmd/
| ├── app/
| | └── main.go
├── internal/
| ├── api/
| | ├── http/
| | | ├── admin/
| | | | ├── admin.go
| | | | ├── admin_test.go
| | | ├── middleware/
| | | | ├── middleware.go
| | | | ├── middleware_test.go
| | | ├── server/
| | | | ├── server.go
| | | | ├── server_test.go
| | | | └── router.go
| ├── config/
| | ├── config.go
| ├── util/
| | └── util.go
├── pkg/
| ├── admin/
| | ├── repository/
| | | ├── admin_repository.go
| | | ├── admin_repository_test.go
| | ├── service/
| | | ├── admin_service.go
| | | └── admin_service_test.go
| | ├── admin.go
| | └── admin_test.go
├── scripts/
| ├── build.sh
| ├── run.sh
| ├── test.sh
├── deployment/
| ├── Dockerfile
| ├── docker-compose.yml
| └── kubernetes.yml
├── .env
├── Makefile
├── README.md
├── go.mod
└── go.sum

This Go project layout is organized into several directories with specific responsibilities:

cmd: contains the main applications or binaries that are meant to be executed. In this case, there is only one application, app, and it is located in a subdirectory named cmd/app. The main.go file contains the entry point of the application.

internal: contains the internal packages that should not be imported by the applications outside of the project. It's organized into several subdirectories, each with a specific responsibility:

api: contains the HTTP API implementation. Notice that there is a possibility to add other API implementations, like gRPC.

config: contains the configuration package. Environment variables are loaded into config and are used from there. Parts of config are passed down to lower layers.

util: contains the utility package that consists of smaller helper functions.

pkg: contains the packages that can be imported and used by other Go projects. It's organized into several subdirectories, each with a specific responsibility:

admin: contains the package that implements the admin functionality. Packages categorized by business function can be added at this level in any quantity.

admin/repository: contains the package that implements the admin repository. The repository layer is that it should be accessed through an interface, so the implementation can be easily replaced when it’s needed.

admin/service: contains the package that implements the admin service.

scripts: contains scripts used for building, testing, and running the application.

deployment: contains the deployment files for the application, including a Dockerfile, a docker-compose file, and a Kubernetes file.

.env: contains the environment variables used by the application.

Makefile: contains the makefile used to build, test, and run the application. In addition to other functionalities, including mock and documentation generation in this file can be beneficial.

README.md: contains the documentation for the application.

go.mod and go.sum: contain the Go module definition and the checksums of the dependencies.

Wrapping Up

In conclusion, this Go project layout provides a well-organized structure for developing and deploying a web application. By separating concerns into specific directories, this layout promotes modularity, reusability, and encapsulation of internal packages, reducing coupling between packages. I hope this layout serves as a useful guide for developers looking to structure their Go projects in a clean and maintainable manner.

--

--

Mike Dyne
Evendyne

I write articles in various software engineering topics. Read every story from me by subscribing here: https://medium.com/@mikedyne/membership