[{"data":1,"prerenderedAt":184},["ShallowReactive",2],{"article-/articles/monorepo-release-flow-using-changesets":3},{"id":4,"title":5,"alt":6,"author":7,"body":8,"created_at":173,"description":174,"extension":175,"image":176,"meta":177,"navigation":178,"path":179,"seo":180,"state":181,"stem":182,"tags":6,"updated_at":6,"__hash__":183},"articles/articles/monorepo-release-flow-using-changesets.md","Release flow with changesets for a PNPM monorepo",null,"Nicolas Rodriguez",{"type":9,"value":10,"toc":161},"minimark",[11,16,51,70,74,81,85,93,97,102,105,111,130,134,149,152],[12,13,15],"h2",{"id":14},"background","Background",[17,18,19,20,27,28,33,34,39,40,44,45,50],"p",{},"At ",[21,22,26],"a",{"href":23,"rel":24},"https://thesio.eu",[25],"nofollow","Thesio"," we extensively use Jira for managing our client projects. As a developer working on client projects we need to keep track of the hours spent on any given task, for that we use ",[21,29,32],{"href":30,"rel":31},"https://tempo.io/",[25],"Tempo"," as our time tracking solution, which provides some integrations but those are not available to all solutions, for example myself, I am currently on the ",[21,35,38],{"href":36,"rel":37},"https://zed.dev",[25],"Zed"," hypetrain. Unfortunately no integration has been made for it, with the alternative being ",[41,42,43],"em",{},"manually keep track of which tasks I have worked on and how many hours I have spent on them",", I quickly resorted to finding a way to somehow automate this somewhat tedious process. The most tool agnostic way I could think of was creating a ",[21,46,49],{"href":47,"rel":48},"https://github.com/NRodriguezcuellar/tempo-tracker",[25],"Time tracking CLI tool",".",[17,52,53,54,59,60,65,66,69],{},"This tool was originally a monolith, meant to be cloned from source and used locally but even just using it myself I quickly realized that this is a pretty annoying process, especially when using a tool like ",[21,55,58],{"href":56,"rel":57},"https://mise.jdx.dev",[25],"Mise"," to manage my dependencies, because it creates new node environments based on the version you have defined in your mise configuration, so even if you installed the CLI globally it might not be available in the node environment you are currently using. which means I would have to install it globally by pointing to the local directory of the project in every node environment I was using. I decided to bite the bullet and publish it to the ",[21,61,64],{"href":62,"rel":63},"https://www.npmjs.com/package/tempo-tracker",[25],"NPM registry"," something I have actually never done before, which probably increased the chances of ",[41,67,68],{},"someone"," finding it and using it greatly.",[12,71,73],{"id":72},"the-monolith","The Monolith",[17,75,76,77,80],{},"As a monolith publishing and releasing is actually quite straightforward, you build the package and then publish it, it will then make it available using the name and version defined in your ",[41,78,79],{},"package.json"," file. But as I started to add more features and see clear separation of concerns between the different folders in my application I felt the need to turn my monolith into a monorepo, so I could have a clear separation of concerns between the different packages I was creating. For example I had a HTTP server which listened to commands from the client (the CLI) and then some core business logic related to handling the tracked worklogs locally and not all dependencies are interconnected, the Backend for example just needs the Core logic, the CLI might only need the Core too because it does not need to know about the HTTP server. They also use different libraries so there I felt that we could modularize the project, so I set my eyes on migrating to a monorepo approach using PNPM.",[12,82,84],{"id":83},"the-monorepo","The Monorepo",[17,86,87,88,92],{},"The monorepo approach is a great way to manage multiple packages in a single repository. It allows you to share code between packages, manage dependencies more effectively, and streamline the development process. But suddenly my release process was not as straightforward as before, I had to figure out how to publish multiple packages at once, and how to manage the versions of each package. I started looking into different tools and approaches, the one i decided to use was ",[89,90,91],"strong",{},"Changesets",". Changesets is a tool that helps you manage versioning and changelogs in monorepos. It allows you to create a changeset for each change you make, which can then be used to automatically bump the version of your packages and generate a changelog. Although its api is not incredibly complex, the mindset about keeping changesets in your repo which it will automatically consume and use to bump the version of your packages in combination with CI/CD was a bit tricky to wrap my head around.",[12,94,96],{"id":95},"the-release-process","The Release Process",[98,99,101],"h3",{"id":100},"experimental-release","Experimental Release",[17,103,104],{},"At this point I already had a stable version of the CLI published to the NPM registry, and was using it to track my worklogs so I did not want to publish anything to it while I was figuring out the release process. I figured I should have some kind of experimental version of the new packages so I could test it out before eventually publishing a stable version. Although Changesets does have a prerelease functionality, I did not want to use it because I did not have a stable version at all, I want a way to quickly test my monorepo build and publish process first before to get it working exactly like the current stable version of the CLI. I decided to get some inspiration from existing projects, I decided to have a look at some very well known projects that also use changesets and a PNPM monorepo: Vue and React-router. From these two react-router has an experimental release flow which seemed to achieve what I was looking for.",[106,107,108],"blockquote",{},[17,109,110],{},"Good artists copy, great artists steal - Picasso",[17,112,113,114,119,120,125,126,129],{},"As such my ",[21,115,118],{"href":116,"rel":117},"https://github.com/NRodriguezcuellar/tempo-tracker/blob/main/.github/workflows/release-experimental.yml",[25],"experimental release action"," was born, It is quite simple, for the experimental release I will not use changesets at all, I create a manually triggered CI/CD pipeline which will create an experimental branch with the git hash of the chosen branch and then set all the versions of the packages to an experimental version with the git hash as a suffix using a script called ",[21,121,124],{"href":122,"rel":123},"https://github.com/NRodriguezcuellar/tempo-tracker/blob/main/scripts/version.ts",[25],"version.ts",". I will then create a tag called ",[41,127,128],{},"experimental"," and push it to the remote repository. I will then build and publish the packages to the NPM registry.",[98,131,133],{"id":132},"stable-release","Stable Release",[17,135,136,137,142,143,148],{},"Once I had everything tested and working on my experimental branch I felt safe to implement an actual release flow, with releases, changelogs and actual semantic versioning. This turned out to not actually be too complex, I followed the ",[21,138,141],{"href":139,"rel":140},"https://pnpm.io/using-changesets",[25],"guide"," by PNPM itself. I created the ",[21,144,147],{"href":145,"rel":146},"https://github.com/NRodriguezcuellar/tempo-tracker/blob/main/.github/workflows/release.yml",[25],"release action"," once again with inspiration from the react router release action.",[17,150,151],{},"It works by creating release branches, which when pushed to will create a release PR. This release PR will show you what the changes will be when the changesets are consumed and the versions are bumped, together with the changelog items added, allowing you to review and edit any of the changes before merging the PR. When the PR is merged it will trigger the actual publishing process, which will create a new tag and push it to the remote repository, build and publish the packages to the NPM registry and create a release on GitHub.",[17,153,154,155,160],{},"Quite a wonderful experience actually, with which I was able to publish ",[21,156,159],{"href":157,"rel":158},"https://www.npmjs.com/package/@nicorodri/tempo-cli",[25],"the first stable version of the CLI"," to the NPM registry.",{"title":162,"searchDepth":163,"depth":163,"links":164},"",2,[165,166,167,168],{"id":14,"depth":163,"text":15},{"id":72,"depth":163,"text":73},{"id":83,"depth":163,"text":84},{"id":95,"depth":163,"text":96,"children":169},[170,172],{"id":100,"depth":171,"text":101},3,{"id":132,"depth":171,"text":133},"2025-04-26","My journey setting up a release flow for my tempo CLI monorepo using changesets and PNPM","md","https://pnpm.io/img/pnpm-light.svg",{},true,"/articles/monorepo-release-flow-using-changesets",{"title":5,"description":174},"published","articles/monorepo-release-flow-using-changesets","tmID-ZkT4KuHGU-VfC6vqwNGZAHxZ2ZBS8DSb3slEwk",1760637672661]