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.
Find a file
Romain Fallet 17a3f5f340
All checks were successful
Continuous Integration / CI (push) Successful in 45s
docs(README): improve Github Actions example
2025-10-27 21:03:29 +01:00
.forgejo/workflows ci: remove unused runs keyword 2025-10-03 23:41:48 +02:00
.vscode chore: add .vscode/settings.json to configure IDE actions 2025-09-22 22:57:41 +02:00
src fix: apply script filter at the end of the process to avoid loosing dependent workspaces 2025-10-06 21:02:27 +02:00
tests fix: apply script filter at the end of the process to avoid loosing dependent workspaces 2025-10-06 21:02:27 +02:00
.gitignore build: add build script 2025-09-23 11:35:15 +02:00
.npmrc chore: add check strict engines version check 2025-10-03 22:51:15 +02:00
.releaserc.json fix: trigger new release 2025-09-23 12:27:29 +02:00
biome.json ci: add lint script 2025-09-22 22:55:54 +02:00
LICENSE feat: affected command 2025-09-22 18:02:08 +02:00
package-lock.json build: remove SWC to simplify toolchain 2025-10-03 22:02:40 +02:00
package.json chore: add check strict engines version check 2025-10-03 22:51:15 +02:00
README.md docs(README): improve Github Actions example 2025-10-27 21:03:29 +01:00
tsconfig.json build: remove SWC to simplify toolchain 2025-10-03 22:02:40 +02:00

Workspace Tools CLI

Tired of JavaScript dev tooling bloat ?

Workspace Tools 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 @workspace-tools/cli

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

Usage

npx workspace-tools 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: 23

    - 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.