Monorepos with Yarn Workspaces

JavaScript

With monorepos, we keep the code for different projects together in one big repository. This makes sharing and reusing the code across multiple projects easier and can simplify dependency management.

Each project has its own directory, scripts, and dependencies. We can use Yarn workspaces designed with monorepos in mind to handle all that. In this article, we explore the principles behind Yarn workspaces and learn how to use them.

If you want to see out the full code from this article, check out this repository.

Introducing Yarn Workspaces

A workspace is a package within a larger multi-package monorepo. Each workspace is a standalone unit that can define its dependencies and scripts.

Yarn is an alternative to NPM. While NPM supports workspaces as well, it was Yarn that introduced them.

First, we need to install Yarn.

Now, we must create an appropriate directory structure.

In our case, we are creating a very straightforward API to manage articles. We also want to create a simple logger library to log information to the terminal.

We start by creating a file in the workspace root directory.

package.json

A few important things are going on above. First, we must mark the in the workspace root as private. Thanks to that, NPM will refuse if we try to publish it by accident.

We also have to point to all our workspaces. We could list them all separately like this:

However, we would have to modify this list whenever we add another workspace to the or directories. Thanks to using and , Yarn immediately recognizes all new projects.

Creating a reusable library

We have to create separate files for all workspaces in our monorepo.

While we could also mark the libraries as private, Yarn doesn’t force us to. We could publish individual libraries to NPM if we want to.

libraries/logger/package.json

What’s important is that it makes sense to define a prefix for all our libraries, such as . Thanks to that, the names of our libraries won’t collide with packages published to NPM.

We also should define the primary entry point of our library through the property in our .

Our library is straightforward and focuses on logging messages into the console. The color of the notification depends on the severity of the log.

libraries/logger/index.ts

Using the library

Let’s create a simple app that uses our library.

Since our application is a workspace, it needs a separate file.

apps/articles-manager-api/package.json

What’s important is that above, we use . This means that we want to always use the latest version of the library.

apps/articles-manager-api/index.ts

Above, we create a very simplistic API. If you want to know how to create a fully-fledged API with Node.js, check out the API with NestJS articles series.

Thanks to using it, our can import the library like any other package.

Installing the dependencies

What’s crucial is that we don’t have to install the dependencies of each workspace directly. Instead, we must go to the root of our monorepo and run only once. When we do that, Yarn installs the dependencies of all our workspaces at once.

What’s more, Yarn hoists all the dependencies to the top of the monorepo. This means that all of them are located in a single at the top of our monorepo. It makes the process of installing dependencies more efficient.

It is important to note that Yarn did not create a copy of the library but created a link and put it into the at the root of our project. Thanks to that, we don’t have to run every time we make a change in the library.

It is also worth noticing that Yarn created a small directory in the project. It contains the directory with links to executable scripts such as . Thanks to that, when we run the command in the , it can access the dependencies even though the actual packages are hoisted to the root .

apps/articles-manager-api/package.json

Tools like Lerna

Yarn Workspaces efficiently handle dependencies and link packages. Tools such as Lerna that are designed to work with monorepos support Yarn Workspaces and add more features. For example, Lerna can generate changelog information, publish packages, and automatically increment versions of packages.

Lerna was created before Yarn introduced the Workspaces feature and used a linking mechanism to symlink packages together. However, it’s been a long time since Lerna started supporting Yarn Workspaces instead of doing the heavy lifting itself.

Summary

Monorepos can simplify code sharing and dependency management. In this article, we went through how Yarn Workspaces work and how they use the directory efficiently. Even if we want to move on to tools like Lerna, transitioning to other solutions is smoother if we have a foundational understanding of Yarn Workspaces. All of the above makes Yarn Workspaces a solid choice that allows us to handle multiple projects within a single repository.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments