DEV Community

Jono M
Jono M

Posted on

Joys and woes of monorepos

Monorepos are a great concept, especially in environments like Node.js which encourage having many small packages.

There are some very obvious advantages to this: not having to have a bunch of folders open and not having to push to seventeen different repos when you update a shared library is very nice. There are also some less obvious advantages, and as you get deeper into monorepos certain disadvantages start rearing their ugly heads as well. These are just a few good and bad points I've found in my own work that might be worth thinking about.

I've mainly used Yarn 1 workspaces as monorepo tooling so the benefits and problems may not apply to other tools, but I assume the underlying ideas are similar and I'm curious to try out other tools to compare.

Standardised tooling

One of the greatest things about a monorepo is that you can centralise a lot of tooling configuration. For example, chuck a .prettierrc in the root of your monorepo and you'll never have arguments about code style again. Put a few base tsconfigs in the there to extend, and suddenly TypeScript behaves with beautiful consistency across all your packages. Add formatting, linting and husky as dependencies in the root of your workspace and you no longer need to work through upgrading everything individually when a new version comes out.

This is especially true in a team, and even more especially true if you often spin up new packages. Keeping the tooling consistent makes it vastly easier to jump back and forth between packages your team and other teams have worked on.

Dependencies within the repo just work

Something I discovered embarrassingly recently is that if you have a monorepo package that depends on other packages in that repo, and you don't need to publish it (for example, it's a frontend app you bundle anyway), you can add non-published packages as dependencies and it just works.

Let's say you have a design system and several frontend apps which depend on it. Those frontend apps are just bundled into single JS files and deployed somewhere, so they don't need to be published. That means you can just put your design system somewhere in the monorepo with "name": "my-design-system" in its package.json and then add "my-design-system": "*" to any packages which depend on it - no need to deal with any package registries. Run yarn and you're set.

The way this works is that Yarn will symlink all your workspace packages into node_modules automatically, so they'll be found by the module resolution algorithm anywhere within your monorepo. A very neat idea.

This does however mean that if you try to publish a package that depends on a non-published package everything will work fine in CI because it's in the monorepo, but it'll break horribly on NPM because that non-published dependency can't be found. Bear that in mind!

Hoisting dependencies can cause problems

This is a thorny enough issue that I wrote a separate article about it!

The editor conundrum

Monorepos can grow to be massive and can contain a large number of disparate projects, which raises a conundrum: opening the whole monorepo in your editor makes finding files tricky because there are simply so many, but opening subfolders individually can kill many of the advantages of using a monorepo in the first place.

This is of course a problem with all large projects, but it's especially true of monorepos since their point is to become large and somewhat heterogeneous.


I guess my overall point is that monorepos should be managed with care: they're a great idea and often the only reasonable way of managing projects in environments like Node, but diving in without being aware of the pitfalls can end up causing you endless pain with everything from debugging dependencies to navigating the code.

Best of luck with your own monorepo journey!

Top comments (0)