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.
- Release mode — a symlink to
pnpm-workspace.local.yaml(gitignored) is your optional overlay input.pnpm link:onreplaces the symlink with a merged file via scripts/apply-workspace-overlay.mjs and runspnpm install.pnpm link:offreplaces the merged file with a symlink again and runspnpm 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)
- Create the symlink so pnpm has a workspace config to read:
Then
node scripts/workspace-setup.mjspnpm install. - (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-uirelative to this repo's root. cp pnpm-workspace.local.yaml.example pnpm-workspace.local.yamland edit paths to point at your sibling working copies.
Daily use
| Goal | Command |
|---|---|
| Check current mode | pnpm 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 mode | pnpm install --frozen-lockfile |
After toggling, always re-run pnpm run build.
How to tell if link:on is active
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— alin 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 installcomplains about a missingpnpm-workspace.yamlafter clone: runnode scripts/workspace-setup.mjsto create the symlink.link:onfails with "not found": copy the.examplefile first.- After
link:on, pnpm installs a registry copy anyway: check that the direct consumer declaresworkspace:*(not a semver range). For transitive consumers, add anoverridesentry to the overlay. pnpm publishfails: runpnpm link:offfirst; publishing from an overlay-applied workspace is unsupported.