Software
March 1, 2023

Release management for NX Monorepos - Semantic-release vs Changesets vs Release-it

Consider the size, complexity, development processes, and team preferences before making a choice.

Introduction

Choosing a release-management tool can be a confusing process since there are a lot of options and each one is slightly different from the other. In this document, we will compare three main ones: Semantic-releaseChangesets and Release-it.


Factors used to compare the solutions:

  • Ease of use
  • Popularity
  • Monorepos support (NX in our case)
  • CI/CD integration
  • Ease of customization
  • Conventional-commits support


Challenges

The first challenge is whether the tool supports Monorepos by default. Then, we need to look into the setup and how easy or complicated it is and how straightforward is for the members to use and get started with, we don’t want to be spending days just learning another tool.

Some of these tools use conventional-commits to generate the changelog, which comes with good and bad consequences: 

  • The good result is it can be automated, and we can use tooling like commitzen to enforce the conventional-commits rules
  • The bad is sometimes the commit history can be bloated and requires a rewrite at the end of the PR, or else we will have a very long and messy changelog. 

Another challenge is that we need to use Yahoo Node Package Manager (YNPM) to publish the packages to the Yahoo NPM registry which is unique to my case.


Do we need pre-releases?

A pre-release is a version of a software product that is made available to the public before its final release. Pre-releases are typically made available to a limited audience, such as beta testers or early adopters, to gather feedback and resolve any remaining issues before the final release.


Pre-releases are often labelled as "beta" or "alpha" releases and are considered to be less stable and fully functional than the final release. They are meant for testing purposes only and are not recommended for use in a production environment.


The goal of a pre-release is to identify and fix any remaining bugs or other issues in the software, and to gather feedback from users to improve the final product.


Long story short, this is overkill for an internal UI components library. The consumer base is small, and even the changes are straightforward and not worth the overhead of managing pre-releases. 


Separate vs synced package versions

Synced packages are much easier to implement and support since this is a UI library and all the sub-packages are closely related. As a result, It’s better to have one changelog in the root of the project instead of each directory and all the packages will have the same version.


Comparing the different options

Semantic-release

Semantic-release by default aims to be a fully automated release-management and publishing tool, and the way they achieve that is by enforcing and leveraging conventional-commits. We can have multiple release-branches. The documentation is amazing, and extremely configurable but with more configuration, you always have more complexity and a stepper learning curve.


The biggest problem with this is that it is not built by default for Monorepos. Semantic-release-monorepo is a plugin made by the community to add support for Monorepos, but the last commit made to it was in Mars 2022, and it’s not an official plugin, and it’s not built for Nx workspaces (only Yarn, PNPM and Lerna). As a result, using this plugin will require a good amount of configuration from our end which is effort and time that could be invested elsewhere. Or we’d have to build a similar plugin that will work with NX + Semantic-release.


If the product and the team were bigger, I would favour this. But taking into consideration the human resources we currently have, investing a huge amount of effort to use Semantic-release is more of a drawback than an advantage.

Release-it

To some extent, this is like a baby version of semantic-release, a generic release-management tool that can be used with any project type (doesn’t have to be NPM). It has support for Github releases and changelogs, publishes to NPM and tracks multiple release branches (beta, alpha,...).


Configuration for Monorepos is straightforward, there’s already a Github issue with multiple examples and good templates to get started.


We can’t seem to be able to change or configure the publishing process (Ex: use ynpm instead npm), which means we need to implement our custom way to do that.


NX + Release-it, examples:

  • Synced versions: All the packages have the same version, only one .release-it.json is required at the root of the project.
  • Separate version: Each package is versioned independently, this requires having a different .release-it.json for each package.


Changesets

Built for Monorepos first. The changelogs are stored in the file system it self, not git. This approach is easier to work with and can be also more transparent.


Each package will have its own README from the start, unlike with Release-it where we need to configure that ourselves and have one .release-it.json for per package.


The CLI they provide is quite easy to use and straightforward to use and there’s even a Github bot that forces each PR to have updated the Changelogs.


This is more intended to be used manually where the developers manually update the changelogs. Unlike the other two solutions which are meant to be for the most part fully automated, that requires following the conventional commits standard which can be quite annoying for some teams. This is more straightforward than using the commit messages as sometimes the PR can be bloated with commits (for example A commit that fixes something forgotten in the previous commit, linting,...)


It has a Github Action for publishing, but if you use any other CI/CD tool then you’ll have to implement that manually. In this regard, Semantic-release has the most pre-configured CI/CD setups.


You can find a few popular projects that are using Changesets here.

Conclusion

I would pick Release-it out of all the other options because it’s simple to set up, have enough features for most projects, has good examples and seems great for the size of the project where it’s going to be used. It has, to some extent, the best of both worlds from Semantic-release and Changesets.