Constraints
This page documents the new JavaScript-based constraints. The older constraints, based on Prolog, are still supported but should be considered deprecated. Their documentation can be found here.
Overview
Constraints allow enforcement of rules across workspace packages. For example, these rules might include the following:
- Ensuring the same version of dependencies across packages.
- Prohibiting the use of specific dependencies in packages.
What can we enforce?
Our constraint engine currently supports two main targets:
- Workspace dependencies
- Arbitrary package.json fields
It currently doesn't support the following, but might in the future (PRs welcome!):
- Transitive dependencies
- Project structure
Creating a constraint
Constraints are created by adding a yarn.config.cjs
file at the root of your project (repository). This file should export an object with a constraints
method. This method will be called by the constraints engine, and must define the rules to enforce on the project, using the provided API.
For example, the following yarn.config.cjs
will enforce that all react
dependencies are set to 18.0.0
.
module.exports = {
async constraints({Yarn}) {
for (const dep of Yarn.dependencies({ ident: 'react' })) {
dep.update(`18.0.0`);
}
},
};
And the following will enforce that the engines.node
field is properly set in all workspaces:
module.exports = {
async constraints({Yarn}) {
for (const workspace of Yarn.workspaces()) {
workspace.set('engines.node', `20.0.0`);
}
},
};
Declarative model
As much as possible, constraints are defined using a declarative model: you declare what the expected state should be, and Yarn checks whether it matches the reality or not. If it doesn't, Yarn will either throw an error (when calling yarn constraints
without arguments), or attempt to automatically fix the issue (when calling yarn constraints --fix
).
Because of this declarative model, you don't need to check the actual values yourself. For instance, the if
condition here is extraneous and should be removed:
module.exports = {
async constraints({Yarn}) {
for (const dep of Yarn.dependencies({ ident: 'ts-node' })) {
// No need to check for the actual value! Just always call `update`.
if (dep.range !== `18.0.0`) {
dep.update(`18.0.0`);
}
}
},
};