opam-provided dependencies

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 duniverse.

Initial setup

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 duniverse.

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.

To let 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 duniverse.

To configure opam-monorepo to avoid pulling in package foo, specify it in the list of packages provided by Opam:

depends: [
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: [
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 vendor.

$ 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 duniverse, opam-monorepo calculates the dependencies of the packages to be installed via opam. 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.

The opam-provided subset of dependencies is then excluded from the duniverse packages.

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 opam.

In such cases there are two possibilities:

  1. Install the package in opam, exclude it from duniverse
  2. 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!