If you're working on multiple apps and you want to share code between them - for example common utils, data types or UI components - there are several options available.
I was recently browsing a reddit thread about monorepos and sharing code between multiple apps and someone mentioned:
In my experience a monorepo with code symlinked at the
srclevel is the best. The other options are a pain in the ass
And I wondered - what does "monorepo with code symlinked at the
src level" even mean? And how would you go about setting up something like this?
A bit of browsing through the
yarn docs and I stumbled on this piece:
yarn add link:/path/to/local/folderinstalls a symlink to a package that is on your local file system. This is useful to develop related packages in monorepo environments.
So then a monorepo setup using yarn symlinks would simply consist of several libraries and apps, stored as siblings in one main repository, which reference each other through yarn local dependencies.
This can be a great way to share code if:
- you're looking for a simple solution to share code
- you usually release your apps together (i.e. frontend + backend that share a library)
This might not be the best option if:
- you want to release and publish each package / app independently
- you want to be able to lock the shared package to a specific version, if needed
If you think this might be a good solution for you, read along for a step by step walkthrough of how to set this up.
For the sake of this example, we'll use two projects -
project-b - and a library that I named very bluntly
All the code is available on Gitlab, if you want to check it out yourself.
Our monorepo will simply have all of these as siblings at the root level:
- shared-code - package.json - yarn.lock - project-a - package.json - yarn.lock - project-b - package.json - yarn.lock
Notice how each app / library is completely independent and has its own
yarn.lock file. This is good because it keeps each project simple and fully contained.
shared-code available in both
project-b you can simply run
yarn add link:/path for each:
cd project-a yarn add link:../shared-code cd .. cd project-b yarn add link:../shared-code
This will add
shared-code as a dependency in the
Local development flow
When something is changed in the
shared-code library, does it get automatically refreshed or do you need to always rebuild the package?
The short answer is - it depends.
If you use Create React App, this won't work. First, the app expects the
shared-code library to already be built, and second, the default CRA Webpack config does not detect changes in the
shared-code, as it's outside of its
If you use your own custom setup, you can ensure hot reload by customizing your webpack config to detect changes in the symlinked packages. This is where having all the code under
src might come in handy.
How would this work in CI?
Since all the code is in the same repository, the library will always be available to
yarn install. However,
yarn assumes the
shared-code is already built, so will need to manually do this step when building any of the projects:
# Sample CI build script # 1. First build the `shared-code` cd shared-code yarn install yarn build cd .. # 2. Build the project yarn install # Will symlink `shared-code` to the current `node_modules` yarn build
This might make for a simple way to setup code sharing and a seamless developer experience, but there are several downsides to be aware of.
The most important one is related to the fact that both
project-b always use just one version of the
shared-code - the latest one available at a given point in time.
shared-code is not published to an
npm repository it's not possible to lock in a certain version. This means that there's a high chance that a change needed for
project-a might break
Where to go from here
While this setup is good to get started, with time you might "grow" out of it.
If you notice a lot of your dependencies are duplicated in each of the apps / packages, and you'd like to hoist them to the root level, you might want to look into using Yarn Workspaces.
If you decide you want to publish the packages to an
npm repository and want better versioning and publishing support, you might want to look at Lerna.
I hope you found this useful! Let me know in the comments below if you have any questions or thoughts!