Dev tool = isolated build + simple cache index.
Tools like ocamlformat, odoc, and ocaml-lsp-server exist alongside your
project without polluting its dependency tree.
dune fmt
↓
check index: ~/.cache/dune/index/ocamlformat.0.26.2-<checksum8>
↓ miss
solve + build in isolated context
↓
store binary in build cache (content-addressed)
↓
create index: index/ocamlformat.0.26.2-<checksum8> → db/files/v5/<hash>
↓
symlink: _build/install/default/bin/ocamlformat
dune fmt # Installs ocamlformat if needed
dune build @doc # Installs odoc if neededNo configuration. Dune detects when a tool is required, solves dependencies, builds in isolation, and caches the result.
For ocamlformat, create .ocamlformat:
version = 0.26.2
dune tools install ocamlformat # Install + cache
dune tools exec odoc -- --help # Run (auto-install if needed)
dune tools which ocamlformat # Show location| Tool | Package | Compiler-Dependent |
|---|---|---|
| ocamlformat | ocamlformat |
No |
| odoc | odoc |
Yes |
| ocaml-lsp-server | ocaml-lsp-server |
Yes |
| utop | utop |
Yes |
| merlin | merlin |
Yes |
| odig | odig |
Yes |
| ocaml-index | ocaml-index |
Yes |
| dune-release | dune-release |
No |
| opam-publish | opam-publish |
No |
| earlybird | earlybird |
No |
Compiler-dependent tools interact with compiler internals. They must be built with the same OCaml version as the project.
Compiler-independent tools work with any compiler version.
_build/
├── .locks/tools-ocamlformat/ # Lock directory
├── .pkgs/tools-ocamlformat/ # Package builds (isolated context)
└── install/
├── tools-ocamlformat/bin/ # Tool install prefix
└── default/bin/ocamlformat # Symlink to cached binary
~/.cache/dune/
├── db/files/v5/<hash> # Build cache (content-addressed)
└── index/ # Secondary index (simple keys)
├── ocamlformat.0.26.2-a1b2c3d4 → ../db/files/v5/<hash>
└── odoc.2.4.0-f7e8d9c0 → ../db/files/v5/<hash>
The build cache keys on rule hash (all inputs including compiler). For compiler-independent tools, this causes unnecessary cache misses:
Project A (OCaml 5.2) + ocamlformat 0.26.2 → rule hash X
Project B (OCaml 4.14) + ocamlformat 0.26.2 → rule hash Y
Different hashes, different cache entries - even though the binary is identical.
The tool index uses simpler keys that only include what matters:
| Type | Key | Example |
|---|---|---|
| Compiler-independent | <name>.<ver>-<checksum8> |
ocamlformat.0.26.2-a1b2c3d4 |
| Compiler-dependent | <name>.<ver>-<bid8> |
odoc.2.4.0-f7e8d9c0 |
For compiler-dependent tools, the build_id already includes the compiler as a dependency, so separate compiler version in the key is unnecessary.
The index is just symlinks into the content-addressed build cache. One copy of each binary, multiple ways to look it up.
- Compute index key from tool + version (+ build_id if compiler-dependent)
- Check
~/.cache/dune/index/<key> - Hit: follow symlink to cached binary
- Miss: build tool, store in build cache, create index entry
Each tool gets its own build context (tools-<name>). Tool dependencies are
never added to the project's OCAMLPATH:
- No version conflicts with project dependencies
- No accidental imports of tool libraries
- No constraint propagation from tools to project
Dev tools are loaded lazily: resolution and building happen only when the tool is actually needed.
dune build # Does NOT resolve/build odoc
dune build @doc # Resolves and builds odoc (if not cached)This means:
dune buildstays fast even with many dev tools configured- Network access for tool resolution only happens when tools are used
- Compiler-dependent tools don't block builds until documentation/LSP is needed
The lazy loading applies to:
- Dependency resolution (opam solve)
- Source fetching
- Building the tool
Once built and cached, subsequent uses are instant (symlink check only).
For CI or pre-warming the cache:
dune install tools # Install all configured dev tools
dune install tools ocamlformat odoc # Install specific toolsThis is useful for:
- CI pipelines that want deterministic tool availability
- Pre-warming caches before going offline
- Ensuring all tools are ready before starting work
Dev tools use the default repository defined for the workspace.