pnpm overrides cannot force a peerDependency — use a .pnpmfile.cjs readPackage hook to remap it
Situation: a package requires @solana/web3.js@^2 as a peerDependency, but your app cannot upgrade its own @solana/web3.js because other dependencies still need v1. The v2 build is already installed under an alias (for example web3js-experimental). You want the new package to resolve its peer against that alias.
pnpm.overrides does not do this. Neither "$web3js-experimental", "^2.0.0", nor "npm:@solana/web3.js@2.0.0" on the right-hand side of an override entry satisfies a peerDependency — overrides rewrite dependency resolution, not peer requirements.
What works is a readPackage hook, which lets you rewrite a package's manifest at install time: move the peer requirement into a real dependency and delete the peer entry, so pnpm installs a concrete copy instead of complaining.
.pnpmfile.cjs at the workspace root:
const remapPeerDependencies = [
{ package: '@solana-program/compute-budget', packageVersion: '0.6.1',
peerDependency: '@solana/web3.js', newVersion: '2.0.0' },
];
function overridesPeerDependencies(pkg) {
for (const dep of remapPeerDependencies) {
if (pkg.name === dep.package && pkg.version.startsWith(dep.packageVersion)
&& pkg.peerDependencies?.[dep.peerDependency]) {
pkg.dependencies[dep.peerDependency] = dep.newVersion;
delete pkg.peerDependencies[dep.peerDependency];
}
}
}
module.exports = { hooks: { readPackage(pkg) { overridesPeerDependencies(pkg); return pkg; } } };Then reinstall. Match on version prefix as shown, so a future release of the dependency does not silently keep the rewrite.
The consequence to accept: you now have two copies of the library in the graph, which is fine for @solana/web3.js v1 and v2 (different module identities, no shared global state) but is not safe in general. This is a pnpm mechanism, independent of Solana; the same hook solves any unsatisfiable peer.
Source: adapted from a Stack Exchange answer by ngundotra (question by ngundotra), https://solana.stackexchange.com/questions/17553/how-do-i-use-npm-packages-that-require-the-new-web3-js — CC BY-SA 4.0
Confirmed on pnpm 10.34.9 with local tarball packages: an app with lib@1 and a consumer whose peerDependencies has lib ^2. The baseline gives 'unmet peer lib@^2: found 1.0.0'. Adding pnpm.overrides {"consumer>lib": <lib@2>} leaves the same warning, and require('lib') from inside consumer still gets v1. The readPackage hook from the post fixes it: consumer resolves lib v2 while the app keeps v1, and the warning is gone. Your exact code also works for a package with no 'dependencies' field, since pnpm passes a normalized manifest, so pkg.dependencies[...] doesn't throw. A small nit: version.startsWith('0.6.1') also matches 0.6.10-0.6.19. Use an exact compare, or a semver range via require('semver'), if the pin matters.