Config Dependencies

Config dependencies allow you to share and centralize configuration files, settings, and hooks across multiple projects. They are installed before all regular dependencies ("dependencies", "devDependencies", "optionalDependencies"), making them ideal for setting up custom hooks, patches, and catalog entries.

Config dependencies help you keep all the hooks, settings, patches, overrides, catalogs, rules in a single place and use them across multiple repositories.

If your config dependency is named following the pnpm-plugin-*, @*/pnpm-plugin-*, or @pnpm/plugin-* pattern, pnpm will automatically load its pnpmfile.mjs (falling back to pnpmfile.cjs) from the package root.

Config dependencies must come from an npm registry. pnpm verifies them against their registry before installing them, so installing a new or changed config dependency offline requires cached registry metadata. A config dependency pinned with version+integrity keeps that integrity as its pin. minimumReleaseAge applies to config dependencies that are not pinned with version+integrity. pnpm installs them before any updateConfig hook runs, so a minimumReleaseAgeExclude entry added by a hook does not cover them.

How to Add a Config Dependency#

Config dependencies are defined in your pnpm-workspace.yaml. Their integrity checksums are stored in pnpm-lock.yaml (in a dedicated env lockfile document).

For example, running pnpm add --config my-configs will add this entry to your pnpm-workspace.yaml:

pnpm-workspace.yaml
configDependencies:
  my-configs: "^1.0.0"

Since v12.12.0, the saved range follows the same rules as pnpm add. It uses savePrefix, and --save-exact saves the exact version. A dist-tag such as my-configs@latest is saved as a range on the version it resolved to.

How to Update Config Dependencies#

Since v12.12.0, pnpm update updates config dependencies the way it updates the dependencies in package.json:

  • pnpm update moves each config dependency to the newest version its range allows and saves the new range in pnpm-workspace.yaml.
  • pnpm update --latest moves them to their latest version, keeping the range operator.
  • pnpm update my-configs updates only the config dependencies it names. Patterns such as "@myorg/*" are accepted.
  • A config dependency declared with a dist-tag keeps tracking the tag. Only pnpm-lock.yaml moves.

Config dependencies are left alone by --interactive, --patches, --no-save, --filter, and the flags that select dependency groups, such as --prod. A config dependency pinned with version+integrity is not updated.

Important:

  • Config dependencies cannot have their own regular dependencies. They can declare optionalDependencies, but only one level deep — optionalDependencies of optionalDependencies are ignored.
  • Config dependencies cannot define lifecycle scripts (like preinstall, postinstall, etc.).

Platform-specific binaries via optionalDependencies#

A config dependency may ship platform-specific binaries via optionalDependencies, the same pattern used by tools like esbuild and swc. Each platform-binary package declares its supported platform with os, cpu, and/or libc fields, and pnpm installs only the variant that matches the current host. The matching binary is symlinked next to the parent config dependency in the global virtual store, so require('my-config-platform-arch') from inside the config dependency resolves at runtime.

The env lockfile records all platform variants regardless of host platform, so the lockfile stays portable across machines.

Each entry in optionalDependencies must be declared with an exact version (e.g. "1.2.3") — ranges ("^1.0.0", "~1.0.0") and tags ("latest") are rejected. This keeps config-dep installs reproducible: the resolved subdep can't drift between machines for a parent that's pinned by integrity.

Usage#

Installing Dependencies Used in Hooks#

Config dependencies are installed before hooks from your .pnpmfile.mjs are loaded, allowing you to import logic from config packages.

Example:

.pnpmfile.mjs
import { readPackage } from '.pnpm-config/my-hooks'

export const hooks = {
  readPackage
}

Updating pnpm Settings Dynamically#

Using the updateConfig hook, you can dynamically update pnpm’s settings using config dependencies.

For example, the following pnpmfile adds a new catalog entry to pnpm's configuration:

@myorg/pnpm-plugin-my-catalogs/pnpmfile.mjs
export const hooks = {
  updateConfig (config) {
    config.catalogs.default ??= {}
    config.catalogs.default['is-odd'] = '1.0.0'
    return config
  }
}

If you install it as config dependency:

pnpm add --config @myorg/pnpm-plugin-my-catalogs

Then you can run:

pnpm add is-odd@catalog:

This will install [email protected] and add the following to your package.json:

package.json
{
  "dependencies": {
    "is-odd": "catalog:"
  }
}

This makes it easy to maintain and share centralized configuration and dependency versions across projects.

Loading Patch Files#

You can reference patch files stored inside config dependencies.

Example:

pnpm-workspace.yaml
configDependencies:
  my-patches: "1.0.0"
patchedDependencies:
  react: "node_modules/.pnpm-config/my-patches/react.patch"