Alpha Version: You are viewing the ALPHA documentation. This is an experimental version and may contain breaking changes.
Skip to main content

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 commandsrc/*.res.mjstests/*.res.mjs
cd rescript/rescript-effect && rescript buildcompiledcompiled
rescript build (from monorepo root)compileddeleted

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

  1. Remove the package from root rescript.json dependencies if no other root-level source actually imports from it. This prevents the root build from touching the package at all.
  2. Always build from within the package when you need test outputs (e.g. before running tests).
  3. Run Lerna build (npm run build at 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:

  1. Is the source directory listed as a separate top-level entry in "sources" (not under src)? → Move it into src/.
  2. Does the src source entry have a "public" field? → Remove it if not necessary; it can suppress compilation of sibling directories.
  3. Does lib/bs/ only contain artifacts for the src modules? → Confirms the root build is skipping the other directory.