ReScript Monorepo Build Behaviour
How the root build handles dependency packages
When rescript build runs from the monorepo root, it processes all packages listed in the root rescript.json "dependencies" array. Each dependency is compiled using its own rescript.json for source structure, but inherits the root's "package-specs" (module format, suffix, in-source flag).
Critical distinction: when a package is compiled as a dependency, the build system only compiles its src source tree. Source directories listed as separate top-level entries in "sources" (e.g. a standalone "examples" or "example" entry) are not compiled from a root build. They are only compiled when that package is the root of the build invocation (i.e. you run rescript build from within the package directory itself).
This is true regardless of whether those directories have "type": "dev" or not.
The "public" field and compilation scope
Setting "public": ["ModuleName"] on a source entry signals that only those modules are exposed to consumers. In practice, when the package is built as a dependency, the build system may further restrict compilation to only those public modules, skipping any other source directories that contribute no public modules.
Consequence: a "public" constraint on src can silently prevent sibling source directories (like examples) from compiling in dependency builds.
The correct pattern for example files
Place example files inside src/ as a subdirectory (e.g. src/examples/). Because src is always compiled in both root and standalone builds, example files will always be compiled:
"sources": [
{
"dir": "src",
"subdirs": true
}
]
src/
Uuid.res
examples/
Example.res
Do not list examples as a separate top-level source entry alongside src:
// Wrong — examples are skipped in root dependency builds
"sources": [
{ "dir": "src", "subdirs": true },
{ "dir": "examples", "subdirs": true }
]
Dev sources are excluded — and deleted — in dependency builds
When a package declares a source directory with "type": "dev", that directory is only compiled when the package is the root of the build. When compiled as a dependency (e.g. from the monorepo root), dev sources are excluded.
Crucially, ReScript doesn't just skip compilation — it actively deletes the compiled output files (.res.mjs) for any dev sources it finds. This means a root-level rescript build will wipe out test output files that were previously generated by a package-level build.
Example: rescript-effect
// rescript/rescript-effect/rescript.json
{
"sources": [
{ "dir": "src", "subdirs": true },
{ "dir": "tests", "subdirs": true, "type": "dev" }
]
}
// root rescript.json (excerpt)
{
"dependencies": ["@reventlessdev/rescript-effect", ...]
}
What happens:
| Build command | src/*.res.mjs | tests/*.res.mjs |
|---|---|---|
cd rescript/rescript-effect && rescript build | compiled | compiled |
rescript build (from monorepo root) | compiled | deleted |
After a root build, the test .res.mjs files are gone. Running npm run build from within the package (or a Lerna run build that enters each package) restores them.
Workarounds
- Remove the package from root
rescript.jsondependencies if no other root-level source actually imports from it. This prevents the root build from touching the package at all. - Always build from within the package when you need test outputs (e.g. before running tests).
- Run Lerna build (
npm run buildat monorepo root via Lerna) which enters each package and builds it as root, preserving dev sources.
Why this matters for CI
If your CI pipeline runs a root-level rescript build followed by per-package npm test, the test files may be missing. Either:
- Use Lerna's per-package build instead of a root ReScript build, or
- Run the package-level build before running tests for that package.
Diagnosing the same issue in future
If a compiled .res.mjs file is present after a package-level build but missing after a root monorepo build, check:
- Is the source directory listed as a separate top-level entry in
"sources"(not undersrc)? → Move it intosrc/. - Does the
srcsource entry have a"public"field? → Remove it if not necessary; it can suppress compilation of sibling directories. - Does
lib/bs/only contain artifacts for thesrcmodules? → Confirms the root build is skipping the other directory.