Fast, reliable local npm package development tool — a better alternative to yalc.
- Blazing fast — Reflink/CoW + hard links for instant operations on large packages
- Smart linking — Automatically uses the fastest method: reflink → hardlink → parallel copy
- Watch mode — Auto-sync changes to all linked projects
- Monorepo support — Publish all workspace packages at once
- Cross-platform — Works on Linux, macOS, and Windows
- All package managers — npm, yarn, pnpm, and bun
- Full visibility — Know exactly what's linked where
curl -fsSL https://raw.githubusercontent.com/pedrosousa13/lnpm/main/install.sh | shgo install github.com/pedrosousa13/lnpm/cmd/lnpm@latestgit clone https://github.com/pedrosousa13/lnpm.git
cd lnpm
make install# In your library package
cd ~/code/my-library
lnpm publish
# In your app that uses the library
cd ~/code/my-app
lnpm add my-library
# Make changes to my-library, then push updates
cd ~/code/my-library
lnpm push
# Or use watch mode for auto-sync
lnpm watch- Monorepo Guide — Turborepo, Nx, PNPM/NPM/Yarn workspaces integration
- Architecture — System design and implementation details
- Changelog — Version history and updates
- Roadmap — Planned features and improvements
| Command | Description |
|---|---|
lnpm publish |
Publish package to local store |
lnpm add <pkg> |
Add package from store to project |
lnpm remove <pkg> |
Remove linked package |
lnpm push |
Push changes to all linked projects |
lnpm watch |
Auto-sync on file changes |
lnpm status |
Show current project's links |
lnpm list |
List packages in store |
lnpm doctor |
Diagnose issues |
lnpm gc |
Garbage collect unused packages |
lnpm retreat |
Remove all lnpm changes |
lnpm config |
View/edit configuration |
lnpm completion |
Generate shell completions |
# Publish a package
lnpm publish
# Add to a project
lnpm add my-package
# Push updates after making changes
lnpm push
# Or watch for auto-sync
lnpm watch --exec "npm run build"lnpm integrates seamlessly with Turborepo, Nx, and all workspace managers:
# lnpm is installed globally (one-time system install)
# See installation section above
# Publish all workspace packages
lnpm publish --all
# Watch and rebuild with your task runner
lnpm watch --exec "turbo run build --filter=@my/ui"
lnpm watch --exec "nx build my-lib"📖 See MONOREPO.md for complete guides on:
- Turborepo integration
- Nx integration
- PNPM/NPM/Yarn workspaces
- Best practices and troubleshooting
# Remove all lnpm links and restore original dependencies
lnpm retreat --force
npm install # Restore original packages
npm publishQuick setup (recommended):
lnpm completion installThis auto-detects your shell and installs completions. Follow the on-screen instructions to enable.
Alternative - Dynamic loading (add to shell config):
# Zsh (~/.zshrc)
eval "$(lnpm completion zsh)"
# Bash (~/.bashrc)
eval "$(lnpm completion bash)"
# Fish (~/.config/fish/config.fish)
lnpm completion fish | sourceManual installation:
# Zsh
lnpm completion zsh > ~/.zsh/completions/_lnpm
# Bash
lnpm completion bash > /etc/bash_completion.d/lnpm
# Fish
lnpm completion fish > ~/.config/fish/completions/lnpm.fishConfiguration file: ~/.lnpm/config.yaml
# Custom store location (default: ~/.lnpm)
store_path: /path/to/store
# Link mode: "hardlink" (try reflink/hardlink) or "copy" (force copy)
# Default: hardlink
link_mode: hardlink
# Watch debounce in milliseconds (default: 100)
debounce_ms: 100
# Auto-manage .gitignore (add/remove .lnpm/ entry)
# Default: true
manage_gitignore: true
# Patterns to always ignore
default_ignore:
- node_modules
- .git
- "*.log"
# Build scripts and hooks
hooks:
# Skip prepare scripts (prepare, prepublishOnly, prepack)
skip_prepare: false # Default: false (run scripts)
# Skip post-add hook (npm install after add)
skip_post_add: false # Default: false (run npm install)
# Custom hooks (optional)
pre_publish: npm run build
post_add: npm installView/modify config:
lnpm config # Show all
lnpm config store_path # Get value
lnpm config store_path /data # Set value
lnpm config --path # Show config file pathlnpm automatically runs build scripts and dependency installation to ensure packages work correctly when linked.
Before publishing or pushing, lnpm runs these scripts from your package.json (in order of precedence):
prepare— General build scriptprepublishOnly— Runs only on publishprepack— Runs before packing files
Example package.json:
{
"name": "my-library",
"scripts": {
"build": "tsc",
"prepare": "npm run build"
}
}Commands:
lnpm publish # Runs prepare, then publishes
lnpm push # Runs prepare, then pushes
lnpm publish --skip-hooks # Skip prepare scriptsAfter adding a package, lnpm automatically runs npm install (or your package manager) to resolve peer dependencies and install linked package dependencies.
lnpm add my-package # Adds package, then runs npm install
lnpm add --skip-hooks # Skip post-add npm installlnpm validates packages before publishing:
- Checks
package.jsonhasnameandversion - Verifies
mainentry point exists (if declared)
lnpm publish # With validation
lnpm publish --skip-validation # Skip validation (for broken packages)# In your TypeScript library
cd my-library
# package.json has "prepare": "tsc"
lnpm publish # Automatically builds TypeScript → dist/
# In your app
cd my-app
lnpm add my-library # Links and runs npm install
# Make changes to library
cd my-library
# Edit src/index.ts
lnpm push # Rebuilds and updates all linked projectsHusky/git hooks fail during npm install:
- lnpm strips
prepareandprepublishscripts from stored packages (like yalc) - If you see husky errors, re-publish the package:
lnpm publish
Duplicate React or other peer dependency issues:
- Don't use
--installflag; runnpm installmanually with your preferred flags - Or configure npm:
npm config set legacy-peer-deps true
npm ERESOLVE peer dependency errors:
- npm has a bug where
file:dependencies show as@undefined(npm/cli#2199) - When using
--install, lnpm uses--legacy-peer-depsautomatically - Or run
npm install --legacy-peer-depsmanually
Retreat restores wrong version:
- Fixed in latest version - lnpm now properly tracks original versions
- If stuck, manually edit package.json and delete lnpm.lock
Enable debug mode for verbose logging:
# Flag
lnpm --debug publish
lnpm -d status
# Environment variable
LNPM_DEBUG=1 lnpm publishDebug output goes to stderr with timestamps, useful for diagnosing slow operations or unexpected behavior.
- Publish — Uses
npm packrules to determine files, strips lifecycle scripts (prepare/prepublish), then links or copies to~/.lnpm/store/{name}/{hash}/ - Add — Creates reflinks or hard links from store to
project/.lnpm/{package}/, updates package.json tofile:.lnpm/{package} - Symlink — Links
node_modules/{package}→.lnpm/{package} - Push/Watch — Updates store and re-links changed files
- Auto .gitignore — Optionally manages
.lnpm/in.gitignore(enabled by default)
Note: Unlike some tools, lnpm does NOT run npm install automatically (matches yalc). Use --install flag or run manually if needed.
Source Package Store Project
────────────── ───── ───────
src/index.ts ──► (reflink/hardlink)
dist/index.js ──► ~/.lnpm/store/ ══► .lnpm/pkg/ ──► node_modules/pkg
package.json ──► pkg/abc123/ (reflink/hardlink) (symlink)
lnpm uses npm's standard packing rules (via npm pack --dry-run) to determine which files to include, ensuring consistency with actual npm publish behavior. This means:
- Respects
package.jsonfilesfield - Honors
.npmignoreor falls back to.gitignore - Follows npm's default exclusions (
.git,node_modules, etc.) - Additional safety: Explicit
.gitfiltering prevents any VCS files from being linked - Automatic fallback to custom filtering if npm is unavailable
This approach prevents issues with git hooks (like Husky) running in linked packages and ensures lnpm behaves identically to npm publish.
lnpm automatically manages .gitignore entries to prevent committing linked packages (enabled by default, configurable via manage_gitignore: false):
- On
lnpm add— Adds.lnpm/to.gitignorewith marker comment# Added by lnpm - On
lnpm retreat— Removes.lnpm/entry and marker from.gitignore - Smart detection — Skips if pattern already exists
- Atomic writes — Uses temp file + rename to prevent corruption
- Configurable — Set
manage_gitignore: falsein config to disable
lnpm uses an intelligent priority system for maximum performance:
Priority Order: Reflink → Hard Link → Parallel Copy
| Method | Speed | Platform Support | Disk Usage |
|---|---|---|---|
| Reflink (CoW) | Instant | macOS APFS, Linux Btrfs/XFS | Zero (copy-on-write) |
| Hard Link | Instant | Same filesystem | Zero (shared inodes) |
| Parallel Copy | Fast | Always works | Full copy (8 workers) |
Benefits:
- ⚡ 10,000+ files? Instant with reflink or hard links
- 🔄 Copy-on-write — Modify files safely without affecting store
- 🚀 Parallel copying — 4-8x faster when copying is needed
- 💾 Space efficient — No duplication on modern filesystems
lnpm automatically detects the best method and falls back gracefully with helpful warnings.
| Feature | lnpm | yalc |
|---|---|---|
| Link method | Reflink → Hard link → Parallel copy | Sequential copy only |
| Large packages (10k+ files) | Instant (~5ms) on APFS/Btrfs | Slow (~5s+) |
| Watch mode | Built-in | Requires chokidar |
| State tracking | bbolt database | Hash files |
| Monorepo | Native support | Manual |
| Speed | ~10ms startup | ~100ms startup |
| Cross-filesystem | Parallel copy (4-8x faster) | Sequential copy |
| Visibility | lnpm status |
Limited |
- Linux — amd64, arm64
- macOS — amd64 (Intel), arm64 (Apple Silicon)
- Windows — amd64
- Go 1.22+ (for building from source)
- Node.js project with
package.json
Contributions are welcome! Please read our contributing guidelines first.
# Clone and build
git clone https://github.com/pedrosousa13/lnpm.git
cd lnpm
make deps
make build
make testMIT License — see LICENSE for details.
Note: This project was built with assistance from Claude (Anthropic's AI assistant). The architecture, implementation, and documentation were developed through an AI-assisted development process. While the code has been reviewed and tested, users should evaluate it according to their own requirements and standards before use in production environments.