How to setup circleci inside a monorepo

Using CircleCI 2.0 API with pipeline parameters and conditional workflows to run CI per-package in a monorepo.

1 min read
Julien Karst
circlecici-cdmonorepodevops
How to setup circleci for a monorepo

You might want to setup a ci for your monorepo. In this article we will see how to use CircleCI inside a mono-repository. This post assumes that you already have knowledge about monorepo and continuous integration process with CircleCI.

We will use the version 2.0 of the CircleCI API. In this version they allow you to trigger a workflow from an API call. Now you are able to have different workflows between each project inside your monorepo. The main idea here is to trigger workflows based on boolean parameters that you enable or not.

In this article we will not focus on what we exactly do inside our ci and best practices inside circleci. We will only focus on the way we are triggering workflows. You can take a look at the final result on github here.
Parameters

In your file .circleci/config.yml you can define parameters. They are just variables that you can access inside this file. When you trigger CircleCI for this project you can change the value of these parameters.

```yamlversion: 2.1

parameters: # By default we enable the main workflow trigger: type: boolean default: true

# Add a boolean parameter on each package. core: type: boolean default: false

components: type: boolean default: false```

  • We specify the trigger parameter to true. It will be the boolean that triggers or not the main workflow.
  • We've also added one parameter per package (core and components), by default set to false.

Now we've defined parameters. Based on the value of these variables we can enable or not workflows inside our continuous integration process.

Workflows inside the monorepo

Let's look at the workflow configuration part of .circleci/config.yml. We have three different workflows:

  • ci which is the main workflow. It will install dependencies of packages and have the responsibility to trigger other workflows.
  • core defines the workflow of the core package.
  • components defines the workflow of the components package.

```yamlworkflows: version: 2

# The main workflow will trigger other workflow based on your changes trigger: when: << pipeline.parameters.trigger >> jobs:

    • trigger-workflows
    • new_version: requires:
        • trigger-workflows filters: branches: only:
          • master

# Workflows defined for each package. core: when: << pipeline.parameters.core >> jobs:

    • lint: package_name: core

components: when: << pipeline.parameters.components >> jobs:

    • test: package_name: components
    • lint: package_name: components```

You can notice that we have a condition to trigger each of them with the when condition. The condition needs to match with the parameter variable defined previously. This is why we have when: << pipeline.parameters.components >> to trigger the components workflow.

Trigger workflows in a monorepo

In this part we will look at how we trigger different workflows on the monorepo. Here is the job trigger-workflows:

```yamljobs: trigger-workflows: executor: node steps:

    • run: name: Trigger workflows command: node ./circleci.js```

trigger-workflows only runs a javascript file which takes care of triggering workflows. Here is circleci.js:

```javascriptconst fetch = require('node-fetch');const { exec } = require('child_process');

const modules = ['core', 'components'];

exec('npx lerna changed --all', (error, stdout) => { modules.forEach(name => { if (!stdout.includes(name)) return;

const params = { parameters: { [name]: true, trigger: false, }, branch: process.env.CIRCLE_BRANCH, };

fetch( https://circleci.com/api/v2/project/github/${process.env.CIRCLE_PROJECT_USERNAME}/${process.env.CIRCLE_PROJECT_REPONAME}/pipeline, { body: JSON.stringify(params), headers: { Authorization: `Basic ${Buffer.from( process.env.CIRCLE_TOKEN ).toString('base64')}`, 'Content-Type': 'application/json', }, method: 'POST', } ) .then(console.log); });});```

In this file:

  • We execute the command npx lerna changed --all to see packages that have changed.
  • We take the output of that command to see which package changed.
  • For each package that changed, we trigger the CircleCI API and tell it to execute the workflow that corresponds to the name of our package. We also set trigger to false so the base CI will not be executed.

A few notes:

  • CIRCLE_TOKEN is your personal token that allows you to trigger workflows.
  • CIRCLE_PROJECT_USERNAME and CIRCLE_PROJECT_REPONAME are injected by CircleCI so we do not have to care about it.

That's it! You see how to create different workflows and trigger them into your mono-repository. I've added a simple example on github here. The goal of this example is to focus on the way we trigger workflows for a monorepo and not what we are doing inside the workflows. Once you see how to make a workflow for a monorepo you can easily adapt that to your continuous integration needs.

Last updated: February 22, 2026

Julien Karst

Tech Lead & Full-Stack Developer passionate about building exceptional digital experiences.