Getting Started
Syncpack is a command-line tool to manage multiple package.json files.
- Find and fix dependency version mismatches.
- Enforce a single version policy, or create partitions with separate policies.
- Find and bump outdated versions from the npm registry.
- Ensure some dependencies always remain pinned at a specific version.
- Ban some dependencies from being used: anywhere, or in specific places.
- Define rules for where exact or loose semver ranges should be used.
- Assign packages as the source of truth for specific dependencies’ versions.
- Sort and format package.json files consistently.
Quick run
The quickest way to run syncpack to try it is via npx.
Install
It’s best to install syncpack as a dev dependency, so that everyone working on your project uses the same version.
Anyone on the team can now use npm exec to access their local installation of syncpack:
For the rest of this guide I will run synpack as if it is installed globally.
Run
List every dependency in every package.json file in the project:
List only the contents of the dependencies
and devDependencies
objects:
List the versions of packages developed in this project:
Start Small
When setting up a project, I’d recommend that you start small and focus on only production dependencies. Monorepos are large and complex and I think it’s better to tackle them in stages.
Create the following config file at .syncpackrc
in the root of your project:
Now syncpack commands will only inspect the dependencies
properties of package.json files.
Audit
Now take a look at your production dependencies:
You will likely see some warnings, and each warning will display an error code to identify the reason it is invalid. Every warning is explained in the Status Codes documentation.
We’ll look at how to fix mismatching versions, but first let’s look at the semver ranges.
Semver Ranges
Examples of Semver Ranges
Range | Example |
---|---|
< | <1.4.2 |
<= | <=1.4.2 |
"" | 1.4.2 |
~ | ~1.4.2 |
^ | ^1.4.2 |
>= | >=1.4.2 |
> | >1.4.2 |
* | * |
Looking at your syncpack list
output, which semver range is used in the majority of cases?
Supposing you prefer exact version numbers, you can define a policy to standardise them:
What we’ve created is called a Semver Group. Whenever syncpack finds an instance of a dependency, it walks through your semverGroups
array in source code order until it finds a match – the first match wins and syncpack stops searching. An instance can only belong to one Semver Group (and one Version Group, which we’ll see later) and the groups an instance belongs to define the rules that form its version policy.
In our case we’ve decided that every instance under a dependencies
object must always have a semver range of ""
for an exact version number.
We can now check the semver ranges of our production dependencies:
…fix them
…and see that they are now valid
Adding overrides
Sometimes you will have exceptions to a rule, instances which for whatever reason can’t conform to a broader policy and need special treatment. To override a Semver or Version Group, define a more specific one nearer the start of the semverGroups
or versionGroups
array.
For example, to use ^
in just one package we could use the following config, where dashboard-ui
is the name
property of the package.json file we want to make an exception for.
Now when we run syncpack lint-semver-ranges
we will see that dashboard-ui
is invalid because we updated out configuration to expect caret ranges and haven’t updated them yet. When we run syncpack set-semver-ranges
they are fixed to have caret ranges as expected. The rest of the monorepo continues to use exact version numbers for production dependencies.
Version Mismatches
Now that we’re using consistent semver ranges under dependencies
, let’s return to version mismatches.
The most common of syncpack’s Status Codes is HighestSemverMismatch
which tells us that all versions used for that dependency are valid semver, but they are not identical and the one with the highest semver version should be used by all.
If you don’t have any special requirements, they can be fixed automatically
If you see UnsupportedMismatch
warnings, those are cases where there is no semver version (such as a reference to a file or a git hash) and syncpack cannot know what you would want to do.
You can resolve those using an interactive walkthrough:
Adding overrides
We saw earlier how to handle overrides for Semver Groups and Version Groups work in exactly the same way.
A group can be applied to an entire monorepo, specific instances, or anything in between. Groups can be layered over others to apply overrides as we saw in the previous section.
You should hopefully now have a good intuition for how instances get assigned to groups. All that remains is to choose groups which exhibit the behaviour you need and to apply combinations of the dependencies, dependencyTypes, and packages properties to them to target the instances you need to.
Version Groups provide a lot of really useful functionality, let’s look at them some more.
Version Groups
Version Groups create partitions where dependencies inside each group can be internally consistent, without affecting the other groups. They let you handle special cases or provide more specific rules for what to do in certain situations and are best understood by looking at some example use cases.
Incompatible packages using the same framework
A 3rd party framework has had a major update which requires breaking changes but some of your packages can’t easily be upgraded and will need to remain on an older version, while the rest are able to upgrade today.
- You don’t want mismatches between your packages using the latest version of the framework - they should all use eg.
next@13.1.6
andreact@18.2.0
. - You don’t want mismatches between the packages using the old version - they should all use eg.
next@11.1.4
andreact@17.0.2
. - You do want those groups to use different versions to each other and not have Syncpack make them all the same.
- You only have this problem with
next
andreact
, other dependencies can continue to be kept consistent with each other throughout the full monorepo.
Keep going
Update monorepo dependencies
Syncpack can also update dependencies to the latest versions from the npm registry and is best demonstrated by example.
You’ll be guided through an interactive prompt to choose which updates you want to apply.
Next Steps
- Browse the Examples to see some common use cases and how to handle them.
- See what other functionality is provided by Version Groups Banned, Ignored, Lowest Version, Pinned, Same Range, Snapped To, and Standard .
- Read the guide on Local Package Versions, which is an advanced topic.
- If you like Syncpack, tell people about it. Syncpack is a single person project done in what spare time I can find, has been an absolute ton of work, and is completely free.