Monorepo guide
While DMNO works great in a traditional single-purpose repo, it was designed from the ground up to handle the challenges of working in a monorepo.
Monorepo structure
Rather than having only a single .dmno
folder at the root of your project, in a monorepo each child project/service will have its own .dmno
folder too.
Directory/ (root of your project)
Directory.dmno (your root service config)
- config.mts
Directorypackages
Directorymy-package
Directory.dmno
- config.mts (config for my-package service)
Directoryanother-package
Directory.dmno
- config.mts (config for another-package service)
- package.json
If you’re starting fresh with DMNO, then the dmno init
command will detect all your services and help initialize DMNO in each.
Detecting child services
By default, DMNO will rely on your existing tooling to detect where potential child projects are found. This is usually an array of paths or glob patterns.
We look in the following locations:
Workspace tool | Globs location |
---|---|
npm, yarn, bun | package.json └ workspaces |
pnpm | pnpm-workspace.yaml └ packages |
moonrepo | .moon/workspace.yml └ projects |
In some situations, like a polyglot repo, or a large repo that has multiple smaller monorepos within it, you may need an alternate way of defining where to look for DMNO services. In this case, you can create a workspace.yaml
in your workspace root’s .dmno
folder. If this file is found, it will override everything else.
Running concurrent DMNO tasks
When running tasks within a monorepo, you often want to orchestrate many tasks on many child projects at once, using something like Turborepo. Since many of those tasks may rely on DMNO to load and resolve config, this could slow things down due to unnecessary repeated work.
To solve this, dmno run
boots up a server that other DMNO instances within child processes are able to communicate with, meaning we can load and resolve your config just once. To take advantage of this optimization, run your command via dmno run
and you should be good to go - for example dmno run -- turbo build
.
Sharing config across services
As outlined in our schema guide, services in monorepos are allowed to pick
items from other services. While there are other mechanisms for reusing values from other services, pick
allows you to reuse the entire item - including all other properties (e.g., description, validation logic).
If you find your services have duplicate config items, or an item could be derived from one in another service, consider using pick()
to keep things DRY.