Test and build only affected code in your NPM workspaces in a simple and easy way! Built for developers tired to use complex monorepo tools like NX and Lerna.
  • TypeScript 53.3%
  • JavaScript 46.7%
Find a file
Romain Fallet e38b41045c
All checks were successful
Continuous Integration / CI (push) Successful in 29s
fix: 🐛 change display name in console output
2026-06-07 16:43:43 +02:00
.forgejo/workflows ci: 👷 get GH_URL from env instead of secrets 2026-06-03 00:02:52 +02:00
.husky chore: 🔧 add husky commit hooks and devmoji to validate commit messages 2026-06-02 22:03:21 +02:00
.vscode Initial commit 2026-06-02 21:43:39 +02:00
src fix: 🐛 change display name in console output 2026-06-07 16:43:43 +02:00
tests fix: 🐛 change display name in console output 2026-06-07 16:43:43 +02:00
.editorconfig chore: 🔧 add editorconfig 2026-06-02 22:37:20 +02:00
.gitignore Initial commit 2026-06-02 21:43:39 +02:00
.npmrc Initial commit 2026-06-02 21:43:39 +02:00
.releaserc.json Initial commit 2026-06-02 21:43:39 +02:00
biome.json Initial commit 2026-06-02 21:43:39 +02:00
LICENSE Initial commit 2026-06-02 21:43:39 +02:00
package-lock.json chore(deps): 🔗 update @types/node 2026-06-07 16:43:32 +02:00
package.json chore(deps): 🔗 update @types/node 2026-06-07 16:43:32 +02:00
README.md Initial commit 2026-06-02 21:43:39 +02:00
tsconfig.json feat: update typescript 2026-06-02 22:13:06 +02:00

MonoLoom CLI

Tired of JavaScript dev tooling bloat ?

MonoLoom CLI will help you managing your NPM workspaces.

The philosophy :

  • no dependency
  • zero config
  • fast

This tool is NOT for you if :

  • maintaining ever changing NX and Lerna configurations is your purpose in life
  • you love patching your 915092 transitive dependencies (or leaking your credentials in supply chain attacks)
  • you have to convince your boss with jargon like ai-powered-self-healing-ci-cloud-cache-task-splitting-distribution

Why

The difficulty in monorepos is building/testing only what's changed.

The problems with NPM CLI :

  • only allow us to target all workspaces with the --workspaces flag
  • does not fail fast despite this old request

This means that the execution time of continuous integration increases linearly as the monorepo grows. The main objective of this tool is to address these issues.

Installation

npm add --save-dev @monoloom/cli

Simple, right? No npx init scripts, no boilerplate starter CLI, just drop it at the root of your monorepo.

Usage

npx monoloom affected:<npm-script-name>

This command will calculate your dependency graph based on what you have declared in the dependencies key of your package.json files, then execute the provided npm script in a fail fast way with the command npm run <npm-script-name> --workspace /path/to/workspace --if-present.

After each successful command, it will record the state of all workspaces in a .workspaces-state file at the root of the monorepo in order to calculate only what's changed on the next execution.

Keep in mind that as a generated file, the .workspaces-state should not be committed in your git repository and should be added to your .gitignore.

Usage in CI

The ./.workspaces-state file must be cached to improve your workflow execution time in CI.

Github Actions/Forgejo Actions usage

In .github/workflows/ci.yml file:

name: Affected Continuous Integration

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - uses: actions/setup-node@v5
      with:
        node-version: 24

    - name: Restore workspaces state
      id: workspaces-state
      uses: actions/cache/restore@v4
      with:
        path: |
          ./.workspaces-state
        key: workspaces-state

    - name: Install dependencies
      run: npm ci

    - name: Lint affected workspaces
      run: npx workspace-tools affected:lint

    - name: Save workspaces state
      uses: actions/cache/save@v4
      with:
        path: |
          ./.workspaces-state
        key: ${{ steps.workspaces-state.outputs.cache-primary-key }}

Example

Consider this files structure :

package.json
applications/
├─ billing/
├─ test-billing/
libs/
├─ invoices/
│  ├─ package.json

First, the root package.json must contain a workspaces field listing all items inside the monorepo.

./package.json:

{
    "workspaces": [
        "./applications/billing",
        "./applications/test-billing",
        "./libs/invoices"
    ]
}

The billing workspace declares a dependency to the invoices workspace.

./applications/billing/package.json:

{
    "name": "billing",
    "dependencies": {
        "invoices": "*"
    }
}

The test-billing workspace declares a dependency to the application workspace.

./applications/test-billing/package.json:

{
    "name": "test-billing",
    "scripts": {
        "test": "echo \"Running billing tests!\""
    },
    "dependencies": {
        "billing": "*"
    }
}

And the invoices workspace has no dependency.

./libs/invoices/package.json:

{
    "name": "invoices",
}

Note that the name field is the only required field.

License

The code and documentation in this project are released under the GNU General Public License v3.0.