Monorepo with Go: Code Organization for Scalable Projects

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Monorepo with Go: Efficient Code Organization



In modern software development, choosing a code management strategy is one of the key factors affecting team productivity and project scalability. A monorepo is an approach where the code for all services, libraries, and tools is stored in a single repository. Combined with the Go language, which was originally designed for large projects, a monorepo becomes a powerful tool.



In this article, we will explore how to properly organize a monorepo in Go: from the basic directory structure to dependency management using Go Workspace. You will learn how to avoid common mistakes and build an architecture that will grow with your project.



Why Monorepo and Go are the Perfect Pair?



Go (Golang) is renowned for its simplicity and efficiency. However, when working with microservices or large libraries, a question arises: how to organize the code so that it remains easy to maintain and refactor?



Advantages of a monorepo for Go:

  • Single version of dependencies: all services use the same versions of libraries, eliminating conflicts.
  • Simplified refactoring: changing an API in one library is immediately reflected in all consumers.
  • Commit integrity: changes in different parts of the project can be combined into a single commit, simplifying rollbacks.
  • Standardization: unified linting, testing, and CI/CD rules for the entire project.


Moreover, Go provides built-in tools — modules (go mod) and workspace (go work) — which are ideally suited for working with a monorepo.



Basic Structure of a Go Monorepo



A proper directory structure is the foundation of a successful monorepo. Let's look at a recommended organization using an example project with several microservices and a shared library.



myproject/├── apps/│   ├── api-gateway/│   │   ├── cmd/│   │   │   └── main.go│   │   ├── internal/│   │   ├── go.mod│   │   └── go.sum│   ├── user-service/│   │   ├── cmd/│   │   └── internal/│   └── order-service/│       ├── cmd/│       └── internal/├── libs/│   ├── common/│   │   ├── logger/│   │   ├── config/│   │   ├── go.mod│   │   └── go.sum│   └── db/│       ├── models/│       ├── migrations/│       ├── go.mod│       └── go.sum├── scripts/│   ├── build.sh│   └── deploy.sh├── go.work├── Makefile├── .golangci.yml└── README.md


Explanation of the structure:

  • apps/ — contains executable applications (microservices, CLI utilities). Each service is a separate Go module with its own go.mod.
  • libs/ — general-purpose libraries that are reused across services.
  • scripts/ — auxiliary scripts for building, testing, and deployment.
  • go.work — the workspace file that links all modules into a single development space.


Important: do not place code directly in the root of the repository. Use subdirectories to group code by functional purpose.



Dependency Management with Go Workspace



Since Go version 1.18, support for workspace has been introduced. This is a key feature for a monorepo, allowing you to develop multiple modules simultaneously without needing to publish them to a remote registry.



Creating a workspace:

# Initialize workspace in the project rootgo work init ./apps/api-gateway ./apps/user-service ./libs/common

# Add a new modulego work use ./apps/order-service

# View the current workspacego work edit -json


Contents of the go.work file:

Blogs

Book Recommendations