Skip to main content

Overview

The pm link command creates symbolic links between local packages, allowing you to develop and test packages together without publishing them.

Syntax

pm link [...args]

Arguments

args
string[]
Arguments passed directly to your package manager’s link command

Examples

In the package you want to link:
cd ~/projects/my-library
pm link
Output
Running: pnpm link
This makes the package available globally for linking. In the project that needs the package:
cd ~/projects/my-app
pm link my-library
Output
Running: pnpm link my-library
Link directly using a file path:
pm link ../my-library
Output
Running: pnpm link ../my-library

Use Cases

Local Development

Develop a library and application together:
1

Create Global Link

In your library project:
cd ~/projects/ui-library
pm link
2

Link in Application

In your application project:
cd ~/projects/web-app
pm link ui-library
3

Develop and Test

Changes in ui-library are immediately reflected in web-app

Testing Unpublished Changes

Test changes before publishing to npm:
# In library
cd ~/my-package
pm link

# In test project
cd ~/test-app
pm link my-package

# Make changes and test
# Changes are immediately available

Monorepo Alternative

While monorepos handle this automatically, pm link is useful for:
  • Cross-monorepo development
  • Testing packages outside their monorepo
  • Temporary connections between projects

How It Works

From src/commands/link.ts:10-17:
export const linkCmd = cli.Command.make('link', { args: argsArg }, (args) =>
  Effect.gen(function* () {
    const pm = yield* PackageManagerService;
    const passthrough = Array.from(args.args);
    const cmd = ShellCommand.make(pm.name, 'link', ...passthrough);
    yield* Console.log(`Running: ${pm.name} link ${passthrough.join(' ')}`);
    yield* runShellCommand(cmd);
  }).pipe(Effect.provide(PackageManagerLayer)),
);
The command:
  1. Detects your package manager
  2. Passes all arguments to the native link command
  3. Creates symbolic links in node_modules

Package Manager Behavior

# Create global link
pnpm link --global

# Link to package
pnpm link --global my-package

# Link with path
pnpm link ../my-package
pnpm requires --global flag for creating global links. Better PM passes this through automatically.

Verification

Check if a package is linked:
pm ls my-package
Output
[email protected]
└── [email protected] -> /Users/you/projects/my-package
The -> indicates a symbolic link.

Troubleshooting

If changes aren’t reflected:
  1. Rebuild the linked package:
    cd ~/my-package
    pm run build
    
  2. Check if link exists:
    pm ls my-package
    
  3. Re-create the link:
    pm unlink my-package
    pm link my-package
    

TypeScript Issues

For TypeScript projects, you may need:
tsconfig.json
{
  "compilerOptions": {
    "preserveSymlinks": true
  }
}

Build Watch Mode

For real-time changes, run the linked package in watch mode:
cd ~/my-package
pm run build --watch

Best Practices

Remember to unlink before publishing or deploying to avoid development-only dependencies.
  • Document links - Keep track of which packages are linked
  • Use watch mode - Run builds in watch mode for instant updates
  • Unlink after testing - Remove links when done to avoid confusion
  • Consider alternatives - For monorepos, use workspace features instead
  • pm unlink - Remove symbolic links
  • pm ls - List dependencies and check links
  • pm install - Install dependencies normally