Repository navigation
Run root prepare lifecycle script on repeat installs (or expose an install hook) #16545
Copy link
Copy link
Closed
Labels
Description
Context
Since pnpm 11, optimisticRepeatInstall defaults to true, so a repeated pnpm install short-circuits (Lockfile is up to date, resolution step is skipped) and root lifecycle scripts — notably prepare — are not run. pnpm ≤ 10 ran the root prepare on every pnpm install.
Use case
Tools that (re)generate local, non-dependency state on install rely on prepare running on every install:
simple-git-hooks(git hooks) — if.simple-git-hooks.jsonchanges, the hooks in.git/hooksgo stale until a real install happens, and there is no automatic way to refresh them.- codegen / type generation.
Yarn Berry has a plugin for exactly this (run prepare after yarn install): https://github.com/un-es/yarn-plugin-prepare-lifecycle. There is no pnpm equivalent.
What I verified
.pnpmfile.cjshooks (readPackage,afterAllResolved,preResolution,filterLog) only run during resolution, which is skipped on a repeat install, so they cannot be used as a workaround.afterAllResolvedfires on the first install but not on the repeat.optimisticRepeatInstall: falseno longer restores the behaviour in v12: the setting is read (pnpm config get optimistic-repeat-install→false), butpnpm installstill printsLockfile is up to date, resolution step is skippedandpreparedoes not run.- pnpm has no general plugin API (unlike Yarn Berry's install-completion hook), so a userland plugin cannot fill the gap.
Behaviour across versions (repeat install, project with a real dependency, "prepare": "echo PREPARE_RAN"):
| pnpm | prepare on repeat install |
|---|---|
| 7 / 8 / 9 / 10 | runs |
| 11 / 12 | skipped |
Request
One of:
- Restore the pnpm ≤ 10 behaviour when
optimisticRepeatInstall: false— i.e. still run root lifecycle scripts even when the install is otherwise up to date; or - Add a setting to always run the root
prepare(and/or other root lifecycle scripts) on everypnpm install; or - Expose an install-completion hook so a plugin like
yarn-plugin-prepare-lifecyclecan be ported.
Related
- v11 release notes —
optimisticRepeatInstalldefault changed totrue: https://github.com/pnpm/pnpm/releases/tag/v11.0.0 - pnpm install is a no-op when only pnpm-lock.yaml is changed (e.g., git checkout) — regression from v10 #12100 —
pnpm installno-op when onlypnpm-lock.yamlchanged (regression from v10, attributed tooptimisticRepeatInstall) - The
optimisticRepeatInstallcausespnpm installto no-op for most changes inpnpm-workspace.yaml#10393 —optimisticRepeatInstallcausespnpm installto no-op for mostpnpm-workspace.yamlchanges - pnpm install on fresh clone reports "Already up to date" without materializing node_modules in some workspace configurations #12748 — fresh clone reports "Already up to date" without materializing
node_modules - Optimistic repeat install doesn't respect overrides #12892 / fix(deps-status): respect overrides in the optimistic repeat install check #12916 — optimistic repeat install doesn't respect overrides
- pnpm does not run the
preparelifecycle npm scripts, sometimes, after install #3756 —preparelifecycle scripts sometimes not run after install
Activity
github-actions commentedon Oct 3, 2026
@JounQin, are you planning to open a pull request for this? If so, reply here and a maintainer will assign the issue to you, so nobody else starts on the same fix.
JounQin commentedon Oct 3, 2026
yes
zkochan commentedon Oct 3, 2026
I don't know what would be the best solution for this. Maybe we need to skip install using the optimistic skip but then run the hooks anyway every time. Although that would also reintroduce a lot of sf operations to read the scripts. That might make repeat install much slower on huge monorepos.
JounQin commentedon Oct 3, 2026
At least
optimisticRepeatInstall: falseshould run the hooks anyway?My two cents:
zkochan commentedon Oct 3, 2026
I don't know. I am thinking there are two realistic options. Either we accept this as the default and if you want the hook to run on every install, you may disable optimistic repeat install. Or we could only check the lifecycle scripts in the root package.json.
zkochan commentedon Oct 3, 2026
Opened #16566 for this.
On pnpm v11,
optimisticRepeatInstall: falsealready runs the projects' lifecycle scripts, includingprepare, on every repeat install. On v12 that setting didn't help, because the install still ended early oncenode_moduleswas up to date. The PR fixes v12 sooptimisticRepeatInstall: falsebehaves as it does on v11 and v10. The default (optimistic) behaviour stays the same: when nothing changed, the install is skipped and so are its scripts. The PR also documents that, so turning the setting off is the documented way to runprepareon every install. It doesn't add a new setting or hook.Written by an agent (Claude Code, claude-opus-5-5).
fix(install): run project lifecycle scripts on an up-to-date repeat i…
fix(deps): update dependencias no-major (#23)