monolink
v1.2.0
Published
CLI tool to simplify local pnpm package linking in monorepos
Maintainers
Readme
monolink
A CLI tool to simplify local pnpm package linking in monorepos.
The Problem
When linking a monorepo package locally:
- Need to build the package first
- Need to resolve
workspace:*dependencies - Need to link all transitive workspace deps
- Error-prone manual process
The Solution
monolink automates the entire process with simple commands.
Installation
# Install globally
npm install -g monolink
# Or use with npx
npx monolink <command>Quick Start
1. Register a Package (in your monorepo)
cd ~/projects/my-monorepo
# Interactive: shows list of packages to choose from
npx monolink register
# Or specify the package name directly
npx monolink register my-packageThis will:
- ✅ Find all workspace dependencies
- ✅ Build packages in dependency order
- ✅ Register the package globally
2. Link the Package (in your target project)
cd ~/projects/my-app
# Interactive: shows list of registered packages to choose from
npx monolink use
# Or specify the package name directly
npx monolink use my-packageThis will:
- ✅ Add
pnpm.overridesfor all workspace deps - ✅ Run
pnpm install
3. Unlink When Done
# Interactive: shows list of linked packages to choose from
npx monolink unuse
# Or specify the package name directly
npx monolink unuse my-packageCommands
monolink register [package]
Register a package from a pnpm monorepo for local linking.
# Interactive: shows list of workspace packages to choose from
monolink register
# Or specify the package name directly
monolink register 0xtrails
# Skip building
monolink register 0xtrails --no-buildWhat it does:
- Finds the monorepo root (via
pnpm-workspace.yaml) - Scans for all
workspace:*dependencies (recursively) - Builds all packages in topological order
- Saves package info to
~/.monolink/manifest.json
monolink use [package]
Link a registered package to your current project.
# Interactive: shows list of registered packages to choose from
monolink use
# Or specify the package name directly
monolink use 0xtrails
# Skip pnpm install
monolink use 0xtrails --no-installWhat it does:
- Reads the package manifest
- Adds
pnpm.overridesto yourpackage.json - Runs
pnpm install
monolink unuse [package]
Remove a linked package from your project.
# Interactive: shows list of linked packages to choose from
monolink unuse
# Or specify the package name directly
monolink unuse 0xtrails
# Skip pnpm install
monolink unuse 0xtrails --no-installWhat it does:
- Removes
pnpm.overridesfor the package - Cleans up
.monolink-local.json - Runs
pnpm install
monolink unregister [package]
Unregister a package from monolink (removes it from the global manifest).
# Interactive: shows list of registered packages to choose from
monolink unregister
# Or specify the package name directly
monolink unregister 0xtrailsWhat it does:
- Removes the package from
~/.monolink/manifest.json - Does not affect projects that are already using the package
monolink list
List all registered packages.
# List all registered packages
monolink list
# List packages linked in current project
monolink list --localmonolink watch [package]
Watch and rebuild a registered package on source changes.
# Interactive: shows list of registered packages to choose from
monolink watch
# Or specify the package name directly
monolink watch 0xtrails
# Custom debounce delay
monolink watch 0xtrails --debounce 500What it does:
- Watches
src/directories of the package and all its workspace deps - Rebuilds on file changes (debounced)
- Gracefully stops with Ctrl+C
How It Works
Registration Flow
┌─────────────────────────────────────────────────────────────┐
│ npx monolink register my-package │
├─────────────────────────────────────────────────────────────┤
│ 1. Find pnpm-workspace.yaml │
│ 2. Parse workspace patterns │
│ 3. Scan package.json for workspace:* deps │
│ 4. Recursively collect all transitive deps │
│ 5. Topological sort for build order │
│ 6. Build each package in order │
│ 7. Save to ~/.monolink/manifest.json │
└─────────────────────────────────────────────────────────────┘Linking Flow
┌─────────────────────────────────────────────────────────────┐
│ npx monolink use my-package │
├─────────────────────────────────────────────────────────────┤
│ 1. Read ~/.monolink/manifest.json │
│ 2. Generate pnpm.overrides config │
│ 3. Update target package.json │
│ 4. Create .monolink-local.json (tracks linked packages) │
│ 5. Run pnpm install │
└─────────────────────────────────────────────────────────────┘Example
Monorepo Structure
my-monorepo/
├── pnpm-workspace.yaml
├── packages/
│ ├── core/
│ │ └── package.json (name: "@myorg/core")
│ ├── utils/
│ │ └── package.json (name: "@myorg/utils", deps: @myorg/core)
│ └── sdk/
│ └── package.json (name: "@myorg/sdk", deps: @myorg/utils)Commands
# In the monorepo
cd my-monorepo
monolink register @myorg/sdk
# Output:
# 🔗 monolink register: @myorg/sdk
#
# Workspace dependencies:
# • @myorg/utils
# • @myorg/core
#
# Build order:
# 1. @myorg/core
# 2. @myorg/utils
# 3. @myorg/sdk
#
# 🔨 Building packages...
# ✓ @myorg/core built successfully
# ✓ @myorg/utils built successfully
# ✓ @myorg/sdk built successfully
#
# ✓ Successfully registered @myorg/sdk
# In your app
cd ~/my-app
monolink use @myorg/sdk
# Your package.json now has:
# {
# "pnpm": {
# "overrides": {
# "@myorg/sdk": "file:/path/to/monorepo/packages/sdk",
# "@myorg/utils": "file:/path/to/monorepo/packages/utils",
# "@myorg/core": "file:/path/to/monorepo/packages/core"
# }
# }
# }Files
~/.monolink/manifest.json- Global registry of packages.monolink-local.json- Per-project tracking (add to.gitignore)
Tips
- Interactive mode - Run any command without a package name to see an interactive list to choose from
- Add
.monolink-local.jsonto your.gitignore- It's project-specific state - Re-register after major changes - Run
monolink registeragain to rebuild - Use watch mode during development -
monolink watchrebuilds automatically - Multiple packages - You can link multiple packages in the same project
Requirements
- Node.js >= 18
- pnpm
License
MIT
