All skills
antfu avatar

/pnpm

@d02c484 official
by Anthony Fuantfu/skills5.9k stars
335

Node.js package manager with strict dependency resolution. Use when running pnpm specific commands, configuring workspaces via pnpm-workspace.yaml, or managing dependencies with catalogs, patches, overrides, config dependencies, or the global virtual store.

Use this Skill: https://skilld.dev/gh/antfu/skills/pnpm

This session only. Nothing lands on disk.

referencesfeatures-hooks.md

≈1.8k tokens on demand. Your agent reads this file only when SKILL.md points to it.

pnpm Hooks (.pnpmfile.mjs)

pnpm hooks customize installation. Declare them in .pnpmfile.mjs (ESM, preferred) or .pnpmfile.cjs (CommonJS), located next to the lockfile (workspace root for a monorepo).

The modern format uses ESM export const hooks = { ... }. The old CommonJS module.exports = { hooks } still works in .pnpmfile.cjs.

Setup

export const hooks = {
  readPackage,
  afterAllResolved,
  updateConfig,
  beforePacking,
}

Hook reference

Hook When Use
readPackage(pkg, ctx) after a dependency manifest is parsed mutate a dependency's package.json (affects resolution)
afterAllResolved(lockfile, ctx) after resolution mutate the lockfile before it's written
updateConfig(config) before install mutate pnpm's settings (great with config dependencies)
beforePacking(pkg) before pnpm pack/publish tarball customize the published manifest only
preResolution(opts) after reading lockfiles, before resolution inspect/modify lockfile objects
importPackage(dir, opts) when writing to node_modules deprecated (v11.23.0) — opts out of the parallel importer; will be removed
filterLog(log) per log entry deprecated/ignored (v12.0.0) — use loglevel instead

readPackage

Called for every package before resolution. Common uses:

function readPackage(pkg, context) {
  // Add a missing peer dependency
  if (pkg.name === 'some-broken-package') {
    pkg.peerDependencies = { ...pkg.peerDependencies, react: '*' }
  }
  // Pin a transitive version
  if (pkg.dependencies?.lodash) pkg.dependencies.lodash = '^4.17.21'
  // Drop a problematic optional dep
  delete pkg.optionalDependencies?.fsevents
  // Replace a deprecated dep
  if (pkg.dependencies?.['old-pkg']) {
    pkg.dependencies['new-pkg'] = pkg.dependencies['old-pkg']
    delete pkg.dependencies['old-pkg']
  }
  return pkg
}

export const hooks = { readPackage }

Mutations are not written to disk; they only affect resolution. Delete pnpm-lock.yaml to re-resolve an already-locked dependency. Removing scripts here does not stop a build — use the allowBuilds setting instead. To persist a change to a dependency's files, use pnpm patch.

updateConfig

Modify pnpm's own settings programmatically — most powerful when shipped in a config dependency so settings are shared across repos.

export const hooks = {
  updateConfig(config) {
    return Object.assign(config, {
      enablePrePostScripts: false,
      optimisticRepeatInstall: true,
      resolutionMode: 'lowest-direct',
      verifyDepsBeforeRun: 'install',
    })
  }
}
// Add a catalog entry from a plugin
export const hooks = {
  updateConfig(config) {
    config.catalogs.default ??= {}
    config.catalogs.default['is-odd'] = '1.0.0'
    return config
  }
}

Since v12.4.1, config is the resolved configuration (every setting pnpm will act on, from .npmrc, CLI, and defaults; unset keys are absent, not null). It also carries registriesByScope (scope → registry URL; rewrite to redirect fetches) and configByUri (registry URI → credentials). Since v12.3.0 the pnpmfile is loaded by many more commands (run, exec, rebuild, script shortcuts, link, outdated, import, pack, publish, stage publish), so updateConfig settings like extraEnv/extraBinPaths reach spawned processes and hook-provided catalogs resolve at pack time.

beforePacking

Customize the manifest that ends up in the published tarball without touching your local package.json.

export const hooks = {
  beforePacking(pkg) {
    delete pkg.devDependencies
    pkg.main = './dist/index.js'
    return pkg
  }
}

afterAllResolved

export const hooks = {
  afterAllResolved(lockfile, context) {
    context.log(`Resolved ${Object.keys(lockfile.packages || {}).length} packages`)
    return lockfile
  }
}

Finders (pnpm list / why)

Custom predicates used via --find-by:

export const finders = {
  react17: (ctx) => ctx.readManifest().peerDependencies?.react === '^17.0.0'
}
pnpm why --find-by=react17

Custom resolvers & fetchers (advanced)

Register top-level resolvers/fetchers to support new package schemes (e.g. my-protocol:pkg). Each is an object with cheap canResolve/canFetch guards plus resolve/fetch. Custom resolvers run before built-ins; custom resolution type fields must use the custom: prefix.

const resolver = {
  canResolve: (dep) => dep.alias.startsWith('@company/'),
  resolve: async (dep) => ({
    id: `${dep.alias}@${dep.bareSpecifier}`,
    resolution: { type: 'custom:cdn', cdnUrl: '...' },
  }),
}
const fetcher = {
  canFetch: (id, res) => res.type === 'custom:cdn',
  fetch: (cafs, res, opts, fetchers) =>
    fetchers.remoteTarball(cafs, { tarball: res.cdnUrl, integrity: res.integrity }, opts),
}
module.exports = { resolvers: [resolver], fetchers: [fetcher] }

hooks.fetchers was removed in v11 — use the top-level fetchers export instead.

Delegating to built-in fetchers

Instead of fetching itself, a custom fetcher can return a { delegate } envelope naming a complete, fetchable resolution for pnpm to fetch with its built-in path (single-step; a custom-typed delegate is rejected):

fetch: (cafs, resolution) => ({
  delegate: { tarball: resolution.customUrl, integrity: resolution.integrity },
})

Prefer the envelope over calling fetchers.* directly: it is the only form that works in both pnpm and pacquet (the Rust port), where cafs/fetchers arrive as null over IPC.

Related settings

ignorePnpmfile: false                  # ignore the pnpmfile entirely
pnpmfile: ['.pnpmfile.mjs']            # local pnpmfile location(s)
globalPnpmfile: ~/.pnpm/global_pnpmfile.mjs

Hooks vs Overrides

Hooks (.pnpmfile) Overrides (pnpm-workspace.yaml)
Logic JavaScript declarative
Scope any manifest field, config, lockfile, packing versions
Use when conditional/complex fixes simple version pins

Prefer overrides/packageExtensions for simple cases; use hooks for conditional logic, config sharing, or packing tweaks.

Key Points

  • Prefer .pnpmfile.mjs with export const hooks/finders/resolvers/fetchers.
  • New hooks: updateConfig (mutate settings), beforePacking (published manifest), preResolution, importPackage.
  • Pair updateConfig with config dependencies to share settings/catalogs across repos.
  • --ignore-scripts does not disable the pnpmfile; use ignorePnpmfile.
<!-- Source references: - https://pnpm.io/pnpmfile - https://pnpm.io/finders - https://pnpm.io/config-dependencies -->

Source: SKILL.md on GitHub

No alerts3d5 checks · Risk SAFE
  • Gen Agent Trust Hub3d

    This skill is a comprehensive documentation reference for the pnpm package manager. It provides detailed guides on CLI commands, monorepo management, and supply-chain security features. No malicious patterns or security risks were identified.

  • Socket3d

    No alerts

  • Snyk3d

    Risk: LOW · No issues

  • Runlayer7mo

    2/15 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at d02c484. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated 4 days ago
Other metadata
metadata
{
  "author": "Anthony Fu",
  "version": "2026.9.25",
  "source": "Generated from https://github.com/pnpm/pnpm, scripts located at https://github.com/antfu/skills"
}
  • pnpm
  • node-js
  • package-manager
  • workspaces
  • monorepo
  • dependencies
  • lockfile
  • catalogs
  • patches
  • overrides

README badge

README badge for antfu/skills/pnpm

Instructs Claude on pnpm commands, workspace configuration, and dependency management features like catalogs, patches, and overrides. Use this when working with pnpm monorepos, configuring strict dependency resolution, or managing workspace-level dependency versions and package patches.

Generated from the current SKILL.md.

Does this skill work with npm or Yarn projects?
This skill is specifically for pnpm. The SKILL.md includes migration guidance for moving from npm or Yarn to pnpm, but does not provide instructions for managing npm or Yarn projects directly.
What version of pnpm does this skill cover?
The skill is based on pnpm 10.x, generated on 2026-01-28.
Can I use this skill to manage monorepos?
Yes. The skill covers pnpm workspaces with filtering, the workspace protocol, shared lockfiles, and centralized dependency management through catalogs.
What should I check before running pnpm commands in a project?
Check for pnpm-workspace.yaml and .npmrc files to understand the workspace structure and configuration. In CI environments, always use --frozen-lockfile.
Does this skill cover patching and overriding dependencies?
Yes. The skill includes support for patches to modify third-party packages and overrides to force specific versions of dependencies, including transitive ones.

Generated from the current SKILL.md. These answers refresh after source changes.