GitLab CI monorepo setup
GitLab CI/CD is a simple yet powerful continuous integration/delivery tool. It currently offers 2,000 free pipeline minutes per month on public and private repositories.
Recently, I’ve split one of my projects into multiple modules (client, server, docs) using the monorepo architecture. In this article, I’ll explain how to adjust the GitLab CI configuration to support such workflows.
Let’s start with a basic
yarn, but the principle can be applied to any other use case:
The CI pipeline consists of a single
test stage that runs a linter, checks unit tests and makes sure a build doesn’t fail. You might consider splitting those tasks into multiple jobs and/or stages. However, while
build can be run in parallel, the CI setup time may lead to an overall slower pipeline execution.
node_modules and the yarn cache are stored between jobs. Notice that I’m passing the yarn cache folder directly to the
install command (instead of using
yarn config set cache-folder .yarn) because of an open yarn defect.
A basic multirepo has the following structure:
We still have just a single
.gitlab-ci.yml file in the project root, but all sources are split into multiple directories.
To run the CI for both modules, we’ll create two independent jobs:
Some things to consider:
- All paths are relative to the project root, not the subfolder.
- Before every job we have to
cdinto the corresponding subdirectory.
- Every job defines a custom cache by using different
The config file works just fine, but there’s room for improvement:
- Remove code duplicates with extend and variables.
- Split config into multiple files with include.
- Run every module with different node versions to ensure compatibility. At the time of writing a matrix feature is not yet implemented.
Here’s the result:
Just keep in mind that the configuration is always relative to project root, even if it’s defined in a subfolder.
After running the pipeline, we’ll see 4 different jobs:
In the end, there’s nothing special about a monorepo when using GitLab CI. We just have to execute all commands from subdirectories instead of the project root.
For the full code and demo, see this GitLab repository.