Corralling Monorepos with Yarn Workspaces

joshtronic

Maybe not the most popular opinion, but I absolutely love monorepos. When you’re starting a brand new project, it just makes sense to have a single repo and growing things from there. Unfortunately, as projects grow, things can get unwieldy. Next thing you know, back and front end code are sharing dependencies and your package.json has grown to a few hundred lines! Never fear, yarn workspaces can help you tame the savage monorepo.

What yarn workspaces brings to the table is an easy way to link your monorepos together, share dependencies and even pin different versions of the same dependency. It also allows you to quickly install dependencies for all of your subprojects with a single yarn install command.

If you’re coming from a micro-services approach with multiple repositories, you’re probably already familiar with writing and dealing with scripts to bootstrap, connect and keep your repositories connected and in sync.

yarn workspaces lets you do this out of the box so you can focus your time on things like actually coding!

Getting Started

Obviously to use yarn workspaces you will need to have yarn installed. If you don’t, please consult the yarn Installation Page and follow the directions for your particular system.

If you’re working with an existing repository that you are using npm with, all you will need to do is run yarn in the repository. This will generate a yarn.lock file and get things in order for you to use yarn.

For brand new projects, simply yarn init inside of your project directory and follow the prompts!

To set things up for demonstration, I’ve created a brand new project called GatorFarm with a directory for front and back end code as follows:

$ mkdir -p GatorFarm/{backend,frontend}
$ cd GatorFarm
$ yarn init # Proceed through the prompts

Creating a Workspace

For me, the beauty of a monorepo lies in the fact that everything is in one place. One repository to clone and you’ve got everything you need.

As mentioned, this gets really hairy when you have a package.json that includes shared dependencies across multiple subprojects within your monorepo.

This gets even hairier the moment you need to use a specific version of a package in one subproject but want or need to use a different version elsewhere.

To help avoid these kinds of issues, we can treat individual subprojects as their own project, with their own dependencies. To do so, we need to run yarn init within each of the subdirectories we created earlier:

$ cd backend
$ yarn init # Proceed through the prompts
$ cd ../frontend
$ yarn init # And of course these prompts
$ cd ..

If you accepted the default values during yarn init, you will have a project named “backend” in the backend directory and a project named “frontend” in the frontend directory.

The name field within your package.json is what yarn uses to to create a workspace. To actually create a workspace, we will need to edit the package.json file in the root of the GatorFarm project:

$ vim package.json # Developer's choice of editor, obviously, Vim not required ;)

And add a workspaces attribute, with an array of our subproject names. It should look something like this:

{
  "name": "GatorFarm",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": [
    "backend",
    "frontend"
  ]
}

Note that the private attribute should also be present and set to true. Projects using workspaces are not meant to be published so if you didn’t specify this during yarn init you can do so now.

Installing Dependencies

Since we have a package.json in each of our subproject directories, we can add dependencies from the subdirectory for each project. Since we have a subproject for back and front end code, let’s add some of our usual suspects to the back end project:

$ cd backend
$ yarn add express uuid
$ cd ..

We can do the same thing in our frontend directory. We can even pin dependencies to different version numbers, for example, pinning the same uuid package we included in backend to an earlier version in frontend:

$ cd frontend
$ yarn add react uuid@^2
$ cd ..

If you were to try adding a dependency to the root of the workspace, you will be met with opposition from yarn. I’m not here to judge, so if you really want to add a dependency to the root of your workspace / project, you can do so with the -W/--ignore-workspace-root-check argument:

$ yarn add lint-staged -W

Linking Subprojects

We’ve covered adding dependencies to our subprojects, but what about linking our subprojects together so that code can be reused?

To link our subprojects, all you need to do is add the project’s name and version like you would any other dependency:

$ cd backend
$ yarn add frontend@1.0.0

Be warned if you omit the version number, you run the risk of including an external dependency from NPM instead of our local subproject.

It’s also worth noting that generic names like frontend and backend can exasperate this overlap with npm packages, so it may be worth it for you to come up with less generic naming conventions :P

A Fresh Start

We now have a project with two subprojects that’s configured as a yarn workspace. Since we walked through each step to get things up and running, you didn’t get to experience one of the best parts of workspaces, installing all of your project and subprojects dependencies with a single command!

You’re welcome to commit and push your changes and then clone a new copy of your repository if you’d like, or you can just clear out the node_modules directories from the root of the project and each of your subprojects.

Once you have a clean copy of your project, simply run yarn install from the project’s root and bask in the glory of all of your dependencies being installed, across multiple subprojects, with one command! 💪

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#