The question of whether to maintain your codebase as monorepo or polyrepo has become even more puzzling with the rise in popularity of micro-architecture patterns like microservices, micro frontends, and micro apps.
On the one hand, monorepos are great for cross-project code sharing, dependency management, and consistency across the codebase. On the other hand, polyrepos offer more flexibility in managing projects, dependencies, and releases, and give teams the autonomy they need to work independently.
In a way, polyrepos are the more "natural" approach for micro-architecture designs as they allow us to enjoy the benefits of small, simple and autonomous projects without the complexity of a monorepo. Unfortunately, polyrepos come with their own set of challenges, especially when it comes to managing dependencies and ensuring consistency across the codebase.
A solution that combines the best of both worlds
There's a clear need for a solution that combines the best of both worlds: the simplicity and autonomy of polyrepos with the code sharing and consistency of monorepos. This is where Bit comes in. Bit allows you to manage each component of your codebase as a standalone entity, called a "Bit component."
Bit can be integrated into existing monorepos or polyrepos, or it can be used to manage your codebase in a completely decentralized way, without the need for a repository.
The first approach transforms your repository into a fine-grained monorepo, or a composable repository/codebase. The second approach no longer requires a repository at all, as Bit components can be modified, built, versioned, and shared, independently, not coupled to any repository.
Click here for a high-resolution diagram
Composable codebase: maximizing code reuse and simplifying project maintenance
To understand how a composable codebase works, let's first look at how projects are structured in a monorepo. Monorepos typically host two types of projects: libraries and apps (with 'services' included). Libraries are reusable pieces of code that are shared across multiple apps, while apps are standalone projects that use these libraries (and other dependencies).
A composable codebase, on the other hand, consists only of Bit components. A Bit component is both a library and, possibly, an app (i.e, a deployable component). Unlike the common structure of a monorepo, a repository consisting of Bit components will have a simple, "flat" structure that is similar to any other composable design.
Standard Applications/Services | NodeJS Libraries | Bit Components | |
---|---|---|---|
Published to NodeJS Registries | No. | Yes. | Yes. Bit components are published to Bit Platform and possibly other registries like the NPM registry. This includes deployable components or “app components”. Bit components can be installed as standard NodeJS packages. |
Deployable | Yes. | No. | Yes. While all Bit components are published to NodeJS registries, some can also be configured to be deployed. |
Source-of-Truth | Project-level VCS and VCS platforms like Git and Github. | Project-level VCS and VCS platforms. | Either “Bit scopes” and platforms like Bit Platform or project-level VCS and VCS platforms. |
Component-Specific Development Setup and Dependencies | No. Development tools and config, as well as dependencies, are configured on the entire repository or a sub-directory of it. | No. Development tools and config, as well as dependencies, are configured on the entire repository or a sub-directory of it. | Yes. Each Bit component can have its own development setup and dependencies, completely independent of its current repository or its location inside the repository. Development environments/setups are maintained as Bit components and reused by other Bit components, across projects. |
Each Bit component has its source files in its own directory and a single file to serve as its entry point or "main" file. Each Bit component consumes other Bit components via their symlink/installed instance in the node_modules
directory. For example:
# An example of a composable repo
button/
index.ts
button.ts
my-app/
my-app.ts
my-app.bit-app.ts (defines 'my-app' as a deployable app component)
index.ts
node_modules/
@my-scope/button/
index.js -> (symlink for type support and IntelliSense)
button.js -> (symlink) ../../button/button.ts
dist/
index.js (compiled)
button.js (compiled)
@my-scope/my-app/
index.js -> (symlink) ../../my-app/dist/index.ts
my-app.js -> (symlink) ../../my-app/my-app.ts
dist/
index.js (compiled)
my-app.js (compiled)
There is no structural distinction between libraries and apps in a composable codebase. Each Bit component can be consumed by other Bit components and can consume other Bit components, regardless of their type.
This greatly simplifies your project maintenance and management. You can easily understand the relationship between components, manage dependencies, and ensure consistency across the codebase.
Furthermore, every piece of functionality in your codebase (not just utility functions and basic UI elements) is a standalone entity that can be shared, versioned, and updated independently. And the best thing is that it doesn't require additional overhead or complexity. Your code is just "naturally" shareable, reusable, and even portable.
Common issues and challenges for code sharing and reusing are no longer a concern, as Bit takes care of it all, including: dependencies, documentation, build, test, versioning, and even CI/CD.
Decentralized codebase: improving team autonomy and codebase flexibility
A decentralized codebase is one that is not managed in a single repository but is distributed across multiple repositories or even none at all. As mentioned in the table above, when working with Bit components, you decide their source of truth. It can be a project-level repository hosted on a platform like GitHub, GitLab, or Bitbucket, or individual components hosted on the Bit platform.
Depending on your team’s workflow structure, you can choose the source of truth: either the Bit scopes where components are hosted or the project repositories where they are maintained. Choosing the Bit scopes as the source of truth allows you to manage your codebase with fine-grained access-control and build setup, over each component and unparalleled flexibility in managing your codebase.
Repositories can be created and destroyed, components can be moved around, and you can decide where they should be maintained based on your team's or ogranization's workflow and the project's requirements.
Top comments (6)
It'll be great to have a sequel article that explores the different CI solutions for each of these version-control approaches.
Brilliant article. Thanks!
Great Article !!
Good read - any info on potential repo organization efficiency hacks is appreciated.
One day if we were to publish libs, might have to change it up a bit. Bookmarked!
Great article explaining the concept of monorepos. Tools like NX and Turborepo offer great integration through plugins (there are several) to set up integrated or standalone monorepos. I've been using NX a lot more because it has much more support and integrations like NX Cloud for monitoring, build cache, logs, etc.
Really nice!
Do checkout my take : medium.com/stackademic/polyrepo-vs...
All feedbacks welcomed.