In this article, I wanna show how we can create monorepo with Golang and Bazel.
- Go Modules — we wanna use
go modfor managing dependencies
- Shared codebase — we wanna reuse our code in different application
- Test — we wanna run tests on single/all applications
- Build — we wanna build every application separately
These requirements go beyond the definition of monorepo. Okay, let's start.
1. Init go modules
We need to create go mod in our folder:
go mod init monorepo
After this command, we can get go dependence on our project.
2. Create for example two application
Let’s create a folder
packages that folder will have all our applications.
cd main_app && touch main.go && cd ../
cd second_app && touch main.go && cd ../
mkdir shared && touch shared.go - that file for shared code
For example, our application will be use gin like HTTP server:
go get github.com/gin-gonic/gin
3. Create a workspace for our monorepo
In the root folder, we need to create WORKSPACE file with content:
And BUILD file with content:
After we need setup Bazel to use dependence from
go.mod with command:
bazel run //:gazelle -- update-repos -from_file=go.mod
That command will be updating our WORKSPACE file with dependencies from
We finish setup our workspace after that we need to set up our applications.
4. Create a build for applications
Every application in the application folder should have BUILD like an entry point for Bazel
Here we have two sections:
This section has some field full list you can find in the link. I will just describe some of them:
“name” — the name for Bazel, for deps and Bazel resolver
“srcs” — entry points for modules, will be like artifacts
“importpath” — how we should import this module in our applications
“deps” — an array of dependencies
“name” — for the run test
“srcs” — entry points for tests
Let's add some shared content
For creating an application like real life I add a router in both applications with similar content
If you see that package using some dependencies from a shared folder.
And lets create BUILD file for that package:
That file has a section ‘go_library’
“name” — the name for Bazel, for use in dep
“srcs” — the entry point for lib
“importpath” — path for import outside(Bazel will be resolved that alias like webpack in nodejs)
“visibility” — visibility of the module in Bazel
“deps” — dependencies, in this example we have dep from “@com_github_gin_gonic_gin” — it is the internal name of gin, you can get from WORKSPACE file and from our shared handler.
5. Create a shared folder and build
In the previous step, we have a reference on a shared folder.
I create a shared handler for gin like that:
And build for package:
As we see gin in dep too.
I will skip the part in creating code for the second application because it is totally the same. Full code you can find here
Hello every this is real-life example of monorepository with Bazel and go-modules Install Bazel …
6. Let's build and test our applications
For build main application we can use the command:
bazel build //packages/main_app:main_app
That command will be build application and show the path to bin file
For build second application you can use:
bazel build //packages/second_app:second_app
Single application test:
bazel test //packages/second_app/...:all
All applications test:
bazel test //packages/...:all
Bazel can create dep graph with the command:
bazel query 'allpaths(packages/...,//packages/shared/handlers/health:health)' --output graph | dot -Tpng > dep.png
That command will be shown all packages who dependent on health module.
In this example, I showed the basis for creating a monorepo in Go, if you are interested, I will continue the article and tell how to use for example protobuf or general static files in monorepo.