Skip to content

Monorepo CI/CD

A monorepo is a single version-control repository that contains code for multiple projects or services.

In a monorepo, all application and microservice code lives together in one repository (instead of each service having its own repo). This approach can simplify development by making it easier to share code and maintain consistency across services.

Fransys supports deploying such multi-application projects from a single repository, but requires a bit of manual configuration which will be explained in this article.

Scenario: We’ll walk through setting up a monorepo on Fransys using GitHub Actions for CI/CD. In our example, the repository contains two applications, App A and App B, organized in subfolders.

We will create two Fransys application blocks (one for each app) but use the same GitHub repo and a shared CI workflow to build and deploy both.

While using Github here, you can apply the exact same logic to GitLab.

Example Monorepo Structure

For illustration, consider the example repository monorepo-example (GitHub: tutorial-fransys/monorepo-example). Its folder structure looks like this:

monorepo-example/
└── apps/
├── app-a/
│ └── Dockerfile
└── app-b/
└── Dockerfile

Each sub-folder (app-a and app-b) contains the source code and a Dockerfile for that application. Fransys will deploy each app as a separate block using its Dockerfile.

We’ll use GitHub Actions to build each Docker image and update the respective Fransys block on every code change.

Step-by-Step Guide

  1. Create “Block A” in Fransys (for App A).
    Log in to the Fransys dashboard and navigate to your project.

  2. Add a new Docker block for the first app (App A).

    Give it a clear name (e.g. “App A” or “app-a”) to identify it.

    This will create Block A, representing your first application within the Fransys environment.

    Link the GitHub repository to Block A.
    After creating Block A, link it to your monorepo on GitHub. In the block’s settings, choose the GitHub option to connect a repository, and select your repo and branch. Once created, click the “Open merge request” button and go on GitHub.

  3. Configure the GitHub repository for App A.
    Now switch to your GitHub repository to set up the CI workflow for the monorepo:

    • Add a Dockerfile path variable: In your GitHub repo, go to Settings > Secrets and variables > Actions. Under “Repository variables,” create a new variable named DOCKERFILE_PATH_APP_A and set its value to the path of App A’s Dockerfile (for our example, app-a/Dockerfile). This variable will be used by the GitHub Actions workflow to know which Dockerfile to build for Block A. (By using a variable, we make the workflow reusable for multiple apps without hard-coding the path.)

    • Update the CI workflow for Block A: Open the GitHub Actions workflow file that Fransys provided (for example, .github/workflows/fransys.yml or a similarly named file in your repo). Modify it to use the new DOCKERFILE_PATH_APP_A variable instead of DOCKERFILE_PATH. In the workflow YAML, update the lines that specify the Docker build context or file. Find the following snippet, it should be around line 24.

      run: |
      if [[ -z "${{ vars.DOCKERFILE_PATH }}" ]]; then
      echo "DOCKERFILE_PATH=Dockerfile" >> $GITHUB_OUTPUT
      else
      echo "DOCKERFILE_PATH=${{ vars.DOCKERFILE_PATH }}" >> $GITHUB_OUTPUT
      fi

      After editing, it should reference the DOCKERFILE_PATH_APP_A variable:

      run: |
      if [[ -z "${{ vars.DOCKERFILE_PATH_APP_A }}" ]]; then
      echo "DOCKERFILE_PATH=Dockerfile" >> $GITHUB_OUTPUT
      else
      echo "DOCKERFILE_PATH=${{ vars.DOCKERFILE_PATH_APP_A }}" >> $GITHUB_OUTPUT
      fi

      You should also rename the file to something like fransys_app_a.yml.

      Commit these changes to the pull request’s branch.

  4. Test the workflow within a pull request.
    On GitHub, go to the Actions tab to watch the progress.

    Ensure that the build succeeds and the workflow finishes without errors. This confirms that the Dockerfile path variable is set up correctly and that GitHub Actions can build your app.

    If the build fails, check the Actions log – common issues include an incorrect file path or missing permissions. Fix any issues and re-run the pipeline until it passes.

  5. Deploy and verify Block A on Fransys.
    Once the GitHub Actions workflow succeeds (meaning the Docker image for App A was built and presumably pushed/deployed), return to the Fransys app.

  6. In your Application Block A details, you should see that it has picked up the latest commit from your repository.

    Fransys links deployments to Git commits, so Block A will show the newest commit hash or message that was just built. Confirm that Block A is now using the latest image.

    At this stage, your first app (App A) is set up and deployed via CI/CD. 🎉

  7. Repeat for Block B (App B).
    Now follow a similar process for the second application (App B) in the monorepo:

    • Create Block B in Fransys: Add another Application block in the Fransys UI for App B (e.g. name it “App B” or “app-b”). Link this block to the same GitHub repository (monorepo). Now both Block A and Block B are pointing to the single monorepo, but each will correspond to a different sub-folder app.

    • Add DOCKERFILE_PATH_APP_B variable: In the GitHub repo settings, create another repository variable named DOCKERFILE_PATH_APP_B and set it to app-b/Dockerfile (the path for App B’s Dockerfile).

    • Update the CI workflow for App B*

      After linking the block to GitHub, it will have created a .github/workflows/fransys.yml once again, like for block A, modify the file to use DOCKERFILE_PATH_APP_B and rename the file to fransys_app_b.yml

    • Test and deploy App B: Just like with App A, check the GitHub Actions workflow for App B (it should have ran after modifying the workflow). Verify that it passes and builds the image for App B successfully. Then check Fransys: Block B should now detect the latest commit and deploy the second application. You will now have two application blocks (A and B) configured from the same repository, each built via the shared CI template but using different Dockerfile paths.

8- Deploy both blocks.

You now should have 2 properly configured blocks, and be able to deploy them to any cluster !

Final Tips

  • Validate your setup: Double-check that your repository variables (DOCKERFILE_PATH_APP_A and DOCKERFILE_PATH_APP_B) exactly match the Dockerfile locations in your repo. Typos in the path will cause the build to fail. Also ensure each Fransys block is linked to the correct repository and branch (usually the main or a specific branch you are using for deployment).

  • Monitor CI logs: When you push changes or open a pull request, keep an eye on the GitHub Actions logs for each workflow. This will help you catch any build errors or misconfigurations early. If something goes wrong (e.g., the Docker build fails), the logs will indicate what to fix. It’s easier to troubleshoot in CI logs before the change reaches the deployment stage.

  • Confirm deployment on Fransys: After a successful CI run, verify on Fransys that each block reflects the new update. The Fransys UI should show the latest commit ID or a “last deployed” timestamp for your blocks.

  • Auto-deploy: Both blocks are by default on “auto-deploy”, meaning any changes to the repo will deploy the new version automatically, if the were already online.

By following these steps, you’ve configured Fransys to deploy multiple applications from a single monorepo using GitHub Actions. You now have a unified repository and CI/CD pipeline for all your apps, simplifying management and avoiding duplicate repositories. Happy deploying!