# \`dune test\` and test-only dependencies

**URL:** <https://discuss.ocaml.org/t/dune-test-and-test-only-dependencies/17786>\
**Category:** Ecosystem\
**Tags:** dune\
**Created:** [February 7, 2026, 2:47pm UTC](https://discuss.ocaml.org/t/dune-test-and-test-only-dependencies/17786 "2026-02-07T14:47:40Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![anentropic](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/anentropic/32/2509_2.png) [@anentropic](https://discuss.ocaml.org/u/anentropic)\
**Post date:** [February 7, 2026, 2:47pm UTC](https://discuss.ocaml.org/t/dune-test-and-test-only-dependencies/17786/1 "2026-02-07T14:47:40Z")

</div>

Does anyone have a solution for this scenario:

I am building an OCaml library, nothing exciting.

I have some tests for the library, the tests use some test-only deps (e.g. Popper)

I want to be able to:

- install just the base lib deps and run `dune build` to build just the base lib
- install the test deps and run `dune test`

So far it seems like these goals are mutually exclusive.

I can add `:with-test` markers in `dune-project` to separate the deps into a group that has to be installed with `--with-test` flag. That covers the `opam install` separation, but `dune build` still tries to build the tests.

The generated `mylib.opam` file has an entry like:

```auto
build: [
  ["dune" "subst"] {dev}
  [
    "dune"
    "build"
    "-p"
    name
    "-j"
    jobs
    "@install"
    "@runtest" {with-test}
    "@doc" {with-doc}
  ]
]

```

…which makes clear why tests are included.

So I had a chat with an agent…

It said I can do `dune build -p mylib @install` to build just the base lib without tests. Ok, but I’d like to be able to just do `dune build` for the base case, and then add args to apply other cases.

Next it gave me profiles, so now `dune-project` has:

```auto
(test
 (name mylib)
 (build_if
  (= %{profile} test))
...

```

and this lets me do `dune build` without test deps installed.

But now I have to `dune test –profile test` to run the tests. Feels redundant.

I realise this isn’t the end of the world, but I feel like I should be able to configure `dune test` to work without extra args.

The agent says it isn’t possible to have both properties that I want though.

Or any wizards out there have a solution for this?

---

<div class="post-metadata">

**Author:** ![Alizter](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/alizter/32/3735_2.png) [@Alizter](https://discuss.ocaml.org/u/Alizter)\
**Post date:** [February 9, 2026, 12:52pm UTC](https://discuss.ocaml.org/t/dune-test-and-test-only-dependencies/17786/2 "2026-02-09T12:52:06Z")

</div>

`dune build` is `dune build @@default` which translates to “build the ‘default’ alias non-recursively (ignoring subdirs) at the current directory”. When you haven’t manually overridden the `@default` alias it defaults to `@all`. `@all` will build all the executables and libraries in your project, this includes your test executables.

If you don’t want `dune build` to build your test executables, then you can override the meaning of `default` in your workspace-level directory. See here for more information:

> **[@default - Dune documentation](https://dune.readthedocs.io/en/latest/reference/aliases/default.html)**

Here is a similar question from another user recently:

> <https://github.com/ocaml/dune/issues/12821>
>
> I have a library \[xdge\](https://tangled.org/anil.recoil.org/xdge) with test exec…utables that are run from a cram test. 
> 
> \`\`\`
> \> cat test/dune
> (executable
> (name xdg\_example)
> (optional)
> (libraries xdge eio\_main cmdliner fmt))
> 
> (executable
> (name test\_paths)
> (optional)
> (libraries xdge eio eio\_main))
> 
> (cram
> (deps xdg\_example.exe test\_paths.exe))
> \> dune build
> File "test/dune", line 9, characters 21-29:
> 9 | (libraries xdge eio eio\_main))
> ^^^^^^^^
> Error: Library "eio\_main" not found.
> \-\> required by \_build/default/test/test\_paths.exe
> \-\> required by alias test/all
> \-\> required by alias default
> File "test/dune", line 4, characters 17-25:
> 4 | (libraries xdge eio\_main cmdliner fmt))
> ^^^^^^^^
> Error: Library "eio\_main" not found.
> \-\> required by \_build/default/test/xdg\_example.exe
> \-\> required by alias test/all
> \-\> required by alias default
> \`\`\`
> 
> I can't find a way to not build the executables in the default alias. I can't wrap them in \`(test)\` since the executable shouldn't be run: the cram test does that. According to the \[dune docs\](https://dune.readthedocs.io/en/stable/reference/dune/executable.html), \`(optional)\` should work here though:
> 
> \> (optional) is the same as the corresponding field of \[library\](https://dune.readthedocs.io/en/stable/reference/dune/library.html).
> 
> Following that link...
> \> (optional)
> \> If present, it indicates that the library should only be built and installed if all the dependencies are available, either in the workspace or in the installed world.
> 
> Here's a \[CI run\](https://tangled.org/anil.recoil.org/xdge/pipelines/4793/workflow/build.yml) showing the executable is being built in \`dune build\` even when the dependencies aren't available, though. Dune language is 3.20

---

<div class="post-metadata">

**Author:** ![anentropic](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/anentropic/32/2509_2.png) [@anentropic](https://discuss.ocaml.org/u/anentropic)\
**Post date:** [February 9, 2026, 2:46pm UTC](https://discuss.ocaml.org/t/dune-test-and-test-only-dependencies/17786/3 "2026-02-09T14:46:41Z")

</div>

```auto
(alias
 (name default)
 (deps
  (alias_rec lib/all)))

```

is `lib/all` a thing itself that dune recognises, or it’s a placeholder that I should replace with the name(s) of libs that I want build by the default target?

can I put this in `dune-project`? that feels right but the [docs for `alias`](https://dune.readthedocs.io/en/latest/reference/dune/alias.html) are under `dune`

if it has to be in a `dune` file… I have this project structure:

```auto
lib/
  dune
  mylib.ml
  extra.ml
tests/
  dune
  test_mylib.ml

```

do I need to override default alias in both dune files?

ie in `lib/dune` to say “build `mylib`" and in `tests/dune` to say “do nothing”?

(is this a bad project structure?)

---

<div class="post-metadata">

**Author:** ![Alizter](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/alizter/32/3735_2.png) [@Alizter](https://discuss.ocaml.org/u/Alizter)\
**Post date:** [February 9, 2026, 4:44pm UTC](https://discuss.ocaml.org/t/dune-test-and-test-only-dependencies/17786/4 "2026-02-09T16:44:52Z")

</div>

This would go in a `dune` file at the same level as `lib/` and `tests/` since you want to override the meaning of default in that directory.

> [@anentropic](#):
>
> is `lib/all` a thing itself that dune recognises, or it’s a placeholder that I should replace with the name(s) of libs that I want build by the default target?

`lib/all` is something that dune recognises. It’s the `all` alias inside of `lib/`. So having

> [@anentropic](#):
>
> ```auto
> (alias
> (name default)
> (deps
> (alias_rec lib/all)))
> 
> ```

in a `dune` file at your project root would tell dune that the meaning of the `default` alias here is to build `lib/all` rather than the default value of `lib/all test/all`.

This would give the meaning that you want to `dune build` at the root of your project.

---

<div class="post-metadata">

**Author:** ![anentropic](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/anentropic/32/2509_2.png) [@anentropic](https://discuss.ocaml.org/u/anentropic)\
**Post date:** [February 11, 2026, 9:23pm UTC](https://discuss.ocaml.org/t/dune-test-and-test-only-dependencies/17786/5 "2026-02-11T21:23:52Z")

</div>

Thank you!

With this pointer and a bit of thought on my side I have now been able to get my project building the way I wanted

I now have a root `dune` file like:

```auto
(dirs lib test)

(alias
 (name default)
 (deps
  (alias_rec lib/all)))

(alias
 (name runtest)
 (deps
  (alias_rec test/all)))

```

and I can `dune build` just the main lib with no test deps installed

or install test deps and `dune test` to build and run the tests

it’s simpler and cleaner than the mess that Copilot had cobbled together, and I’ve learned a bit about dune

---

<div class="post-metadata">

**Author:** ![anentropic](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/anentropic/32/2509_2.png) [@anentropic](https://discuss.ocaml.org/u/anentropic)\
**Post date:** [February 11, 2026, 9:52pm UTC](https://discuss.ocaml.org/t/dune-test-and-test-only-dependencies/17786/6 "2026-02-11T21:52:13Z")

</div>

hmm, one snag is that `dune build` no longer automatically rebuilds `myproject.opam`

but I now understand one way to fix that…

```auto
(alias
 (name default)
 (deps
  (alias_rec lib/all)
  (file "oktree.opam")))

```

is there another way?

is there anything like `(alias_rec lib/all)` that would mean “all the sugars in my dune-project” or something?
