Monorepo: A productive setup for all your side projects

    When you start a new side project, does your initial setup involve cloning previous projects, cleaning up unwanted code & getting started from there? Do you find yourself copying over the auth layer from your past projects? Do you find it tedious to upgrade all the dependent libraries to the same version? I may have a solution to simplify these processes for you.

    I am always on side projects, sometimes on one & sometimes on many. I am constantly checking out newer tech and working with newer libraries. When I start on new projects, I would clone a previous side-project, remove redundant files & build on top of it. I did this a few times & then I spent some time trying to make a starter kit for myself. I eventually gave this up as I had to maintain the starter kit by updating the libraries and refactoring the code because the new code in my projects was better.

    I read blog posts from companies like Segment, Uber, Pinterest, etc. who were moving from multi-repo to a monorepo. They highlighted the problems & benefits that they saw moving to monorepo. Some of the problems they talked about resonated with me & the issues that I faced with side projects.

    I'll explain why you should consider having a single codebase for your side projects.

    What is a monorepo? A monorepo is a single git repository that holds the source code for multiple isolated applications and isolated libraries, along with their tooling. The word isolated is critical here - monorepo has nothing in common with monolithic apps. You can keep several logical apps inside one repo, for example, a web server and its Android app. The multiple applications can be different from the programming language. The concept of monorepo is relatively old, and Google was one of the first companies to adopt this approach for managing their codebases.

    What are the benefits of a monorepo?

    Shared code and visibility

    Reuse validation code, UI components, backend & frontend utility libraries. This can save you time and effort, as you won't have to constantly copy and paste code from one repository to another. Instead, you can simply import the code you need from the monorepo, which can help you avoid duplication and keep your codebase clean and organized.

    Single set of dependencies

    Use a single version of all third-party dependencies, reducing application inconsistencies. Less actively developed projects are still kept up-to-date with the latest version of a framework, library, or build tool.

    Atomic changes

    Change a server API and modify the downstream applications that consume that API in the same commit. You can change a button component in a shared library and the applications that use that component in the same commit. A monorepo saves the pain of trying to coordinate commits across multiple repositories.

    Project mobility

    Get a consistent way of building and testing different applications. You can confidently change any project and verify that the changes are safe.

    Easier refactoring

    Direct access to all projects makes it easier to refactor the code in a monorepo. Moving the source code between folders is much easier than moving the code between multiple repositories.

    Limitations of using monorepo

    While there are many benefits to using a monorepo for indie projects, there are also some potential drawbacks to consider. Using a monorepo can make it more difficult to deploy your code to different environments. With a monorepo, you have to manage all of your code in a single location, which means that you have to deploy the entire codebase whenever you want to update your application. This can be more time-consuming and difficult to manage than deploying smaller, independent repositories. There are tools like Bazel, Turborepo, Nx etc, which help tackle this problem.

    Having a single repository for all your code also means you have to provide access to all the source code. If you plan to share your side project with multiple people to collaborate, this might be a problem, as they get access to all your side projects. Monorepo becomes a limitation if only some parts of the project is meant to be open-source.

    You can always move from monorepo to multi-repo quickly, but the other way around is difficult.

    Adopting monorepo

    If you have multiple repositories and the limitations above don't apply to you, I would move a few repositories into a single repo. Pick the repositories with similar dependencies or match the projects' dependencies before moving ahead. Mismatch of packages/dependencies is one of the common problems that occur when moving to monorepo. Matching dependencies isn't a must & there are build tools that help you work around this problem, but passing this hurdle will help in a smoother transition during the next steps.

    The next step would be to pick a build system. The best criteria would be to choose a tool that is popular in the ecosystem that you work in. Picking a popular tool ensures that you will likely find all the necessary resources without much effort. Here are a few build tools that are popular in the monorepo -

    • Bazel is Google's monorepo-oriented build system.
    • Yarn is a JavaScript dependency management tool that supports monorepo through workspaces.
    • Gradle is a build automation tool for multi-language software development. Supported languages include Java, C/C++, and JavaScript.
    • Turborepo is a high-performance build system for JavaScript and TypeScript codebases.
    • Nx is a smart, fast and extensible build system with first class monorepo support and powerful integrations.

    The next step is to port over an individual project to build with the build system. The exact steps ahead would vary depending on the build system that you have chosen.

    My Personal Monorepo setup

    I have a monorepo for most of my side projects. Most of my projects are web apps that I develop using typescript. I experiment with different backend & frontend technologies. I am currently using Yarn to build and maintain this codebase. Here is what my codebase structure looks like -

    .
    ├─ .github
    ├── packages
    │   ├── ui-components
    │   │  ├── src/
    │   │  ├── tsconfig.json
    │   │  └── package.json
    │   ├── libs
    │   │  ├── src/
    │   │  ├── tsconfig.json
    │   │  └── package.json
    │   ├── auth
    │   │  ├── src/
    │   │  ├── tsconfig.json
    │   │  └── package.json
    │   ├── slack-playground
    │   │  ├── src/
    │   │  ├── tsconfig.json
    │   │  └── package.json
    │   ├── hyper-server
    │   │  ├── src/
    │   │  ├── tsconfig.json
    │   │  ├── package.json
    │   │  └── Dockerfile
    │   └── hyper-ui
    │   │  ├── src/
    │      ├── tsconfig.json
    │      └── package.json
    ├── package.json
    ├── .gitignore
    ├── .husky
    ├── .vscode
    ├── .prettierrc.json
    └── tsconfig.json
    

    Whenever I have to develop a new app, I can quickly get started by either cloning out an existing one or creating a new project from scratch. And once I start developing, I can reuse the existing UI components to build the application, and the landing page for the website gets created quickly. The auth packages are ready for me & I can easily plugin with simple imports. Any improvements I make are quickly taken care of.

    One of the most important reasons I can maintain the monorepo is because of typescript. Whenever I make changes to an existing function or component, typescript errors out in my face, and I can easily make the changes to get things.

    Should you use monorepo?

    pick monorepo multi repo

    It depends. If you plan to keep the codebase private and think you are the only contributor in the early stages of the project, then start with monorepo. You can always move to multi-repo if you decide to open-source the project or you plan to bring in more developers & you want to keep your project private.

    Built & maintained with 💖 by Deepak Puthraya

    Copyright © 2024 Deepak Puthraya. All rights reserved.