Alpha Version: You are viewing the ALPHA documentation. This is an experimental version and may contain breaking changes.
Skip to main content

Cross-repo dev linking

Live-edit a sibling pnpm-compatible repo (e.g. a reventless-ui working copy checked out next to this one) from inside this repo's build, without edits to committed files and without a publish cycle.

Mechanism

  • pnpm-workspace.base.yaml (committed) is the release-mode workspace definition — the source of truth.
  • pnpm-workspace.yaml (gitignored) is what pnpm actually reads:
    • Release mode — a symlink to pnpm-workspace.base.yaml.
    • Link mode — a regular file containing the merged overlay, carrying a # GENERATED by … header.
  • pnpm-workspace.local.yaml (gitignored) is your optional overlay input.
  • pnpm link:on replaces the symlink with a merged file via scripts/apply-workspace-overlay.mjs and runs pnpm install.
  • pnpm link:off replaces the merged file with a symlink again and runs pnpm install.

Because pnpm-workspace.yaml is gitignored, toggling link mode never shows up in git status — commits are safe in either mode.

Setup (one-time per clone)

  1. Create the symlink so pnpm has a workspace config to read:
    node scripts/workspace-setup.mjs
    Then pnpm install.
  2. (Optional — only if you need cross-repo linking.) Check out the sibling repo next to this one. The example overlay assumes it lives at ../reventless-ui relative to this repo's root.
  3. cp pnpm-workspace.local.yaml.example pnpm-workspace.local.yaml and edit paths to point at your sibling working copies.

Daily use

GoalCommand
Check current modepnpm link:status
Switch to link mode (sibling is live source)pnpm link:on
Switch to release mode (registry version)pnpm link:off
Fresh clone, release modepnpm install --frozen-lockfile

After toggling, always re-run pnpm run build.

Run pnpm link:status. It prints either release mode — pnpm link:off or link mode — pnpm link:on by checking whether pnpm-workspace.yaml is a symlink (release) or a regular file (link).

If you want to verify by hand without the script:

  • Inspect the file. ls -l pnpm-workspace.yaml — a l in the mode column and an arrow means release mode. A regular - means link mode.
  • Inspect recognized workspaces. A sibling package only shows up under its real filesystem path in link mode:
    pnpm list --recursive --depth=-1 | grep reventless-ui

Declaring a cross-repo dep

For a core package to live-link against a sibling workspace package, declare it as workspace:* in that consumer's package.json:

"dependencies": {
"@reventlessdev/reventless-ui": "workspace:*"
}

Publishing rewrites workspace:* to a concrete semver range. Verify before every release with pnpm publish --dry-run.

Transitive deps (important caveat)

pnpm only applies workspace linking to direct declarations. If package A (in this repo) consumes sibling B only through a published intermediate C, then C → B resolves to the registry copy even in link mode.

To force the transitive link, add an overrides entry in your gitignored overlay:

# pnpm-workspace.local.yaml
packages:
- '../reventless-ui/reventless/reventless-ui'
overrides:
'@reventlessdev/reventless-ui': 'workspace:*'

Do not commit this override — it would break release builds.

Sibling repo requirements

The sibling repo must be a valid pnpm workspace target, which means a pnpm-workspace.yaml at its root. The sibling can continue to use npm for its own development via the compat-shim pattern (npm-based sibling + a minimal pnpm-workspace.yaml), described under Sibling migration posture below.

Sibling migration posture

Siblings do not have to migrate to pnpm. The compat-shim approach (npm-based sibling + minimal pnpm-workspace.yaml) is the default recommendation and has no open end-date.

Full migration of a sibling becomes worth it only when a concrete trigger forces it:

  • The sibling starts hitting the same cross-repo fires this repo migrated to escape (symlinks wiped by npm install, file: resolution breaking).
  • The sibling's workspace grows enough that npm's hoisting gets unreliable or a ReScript phantom-dep surface accumulates there too.
  • The sibling needs workspace:* semantics for its own internal deps.
  • Two or more siblings need to link to each other — the compat shim only covers "this repo consumes sibling", not sibling-to-sibling.

When a trigger lands, migrate the sibling the same way this repo was migrated. Budget is shorter than this repo's (half-day to a day) because sibling package counts are smaller and the learnings (hoisted node-linker, link-workspace-packages, overrides migration, Lerna v8 quirks) transfer directly. File a separate per-repo plan; don't preemptively migrate.

Committing in either mode is safe

Because pnpm-workspace.yaml is gitignored, neither link:on nor link:off creates a diff on a tracked file. You can commit while link mode is active — the override changes that link:on merges into package.json are the only tracked write, and link:off restores them from the git index. If you run git status after pnpm link:on and see package.json modified, just run pnpm link:off before committing if you don't intend to change overrides.

Troubleshooting

  • pnpm install complains about a missing pnpm-workspace.yaml after clone: run node scripts/workspace-setup.mjs to create the symlink.
  • link:on fails with "not found": copy the .example file first.
  • After link:on, pnpm installs a registry copy anyway: check that the direct consumer declares workspace:* (not a semver range). For transitive consumers, add an overrides entry to the overlay.
  • pnpm publish fails: run pnpm link:off first; publishing from an overlay-applied workspace is unsupported.