This section documents a feature that’s useful when some dependencies cannot be installed via
opam-monorepo. This workflow isn’t meant for regular use but only as a way to use
opam-monorepo in cases where it wouldn't be otherwise possible.
We suggest minimizing its usage and prefer to use (and contribute)
dune-ports from the
opam-overlays repository. It's usage is safest with leaf-dependencies and those that don’t have dependency intersections with vendored packages. Due to possibly of unexpected interactions, this feature is only meant for advanced users, and the solutions it produces might be in flux.
Sometimes it is not possible to put all your dependencies into the
duniverse, be it due to your dependencies not building with
dune or some tooling that should be just installed via
opam. Such examples include:
- Packages not building with Dune
- Packages that should not be vendored for legal reasons
These users can opt-in to having some of their dependencies provided by
opam instead of
opam-monorepo pulling them into the
With the default configuration,
opam-monorepo runs in full-
duniverse mode, i.e., requiring all the dependencies of your
opam files to be able to be built as part of the
As such it is only recommended that packages are installed via
opam for which there is no way to build them with
dune, e.g., by using the opam-overlays repository with Dune ports.
opam-monorepo know a package is to be installed via
opam, it needs to be marked as such in the Opam file. For this, it needs to be added as normal in the
depends field, as well in addition into the new
x-opam-monorepo-opam-provided field. This field takes a single package or a list of packages to be installed via
opam instead of being pulled into the
opam-monorepo to avoid pulling in package
foo, specify it in the list of packages provided by Opam:
depends: [ "foo" ] x-opam-monorepo-opam-provided: ["foo"]
This can either be specified directly in the Opam file or, if you use Dune to generate Opam files, in the
.template file. In such case, make sure to regenerate the Opam file.
As a shortcut syntax, if there’s only one package, it’s possible to leave out the list and just specify the package itself:
depends: [ "foo" ] x-opam-monorepo-opam-provided: "foo"
After you configured your Opam file, you have to lock the environment.
$ opam monorepo lock
After this succeeds, you will have an
.opam.locked file, which contains all your project’s dependencies (including transitive dependencies). The ones that
opam-monorepo will pull into the
duniverse are marked as
$ opam install --ignore-pin-depends --deps-only ./ --locked $ opam-monorepo pull
How it works
In addition to calculating the dependencies of the packages that will be included in the
opam-monorepo calculates the dependencies of the packages to be installed via
opam-monorepo then writes a lockfile that sets a variable on all the dependencies it will pull, whereas
opam-provided dependencies don't have variables set. In Opam, unset variables are false; thus Opam will ignore the packages that
opam-monorepo will pull.
opam-provided subset of dependencies is then excluded from the
Resolution of dependency overlaps
There are cases where a dependency package appears multiple times in the project’s dependency tree. It’s possible that a package is part of the packages to be included in the
duniverse, as well as packages installed by
In such cases there are two possibilities:
- Install the package in
opam, exclude it from duniverse
- Install the package in
opam, include a duplicate in the duniverse
Both these approaches have advantages and disadvantages.
opam-monorepo currently chooses #2 to maximize the amount of packages that are vendored, thus increasing the size of the reproducible set. Yet this doesn’t mean that two different versions of the package can be installed. The set of packages in Opam and the
duniverse must be co-installable!