# Package Manager

> Package manager rules - pnpm by default, npm as alternative, workspaces, scripts, security, monorepos, catalogs

- Skill: `14bryanespinoza/package-manager` (Agent Skill)
- Install (CLI): `npx skillmds@latest add 14bryanespinoza/package-manager`
- Raw SKILL.md: https://api.skillmd.com/api/skills/14bryanespinoza/package-manager/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: 14BryanEspinoza (https://skillmd.com/u/14bryanespinoza)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/14bryanespinoza/package-manager

---


# Package Manager — Rules and Conventions

---

## 1. Philosophy

1. **pnpm by default** — Faster, disk-efficient, strict with dependencies. Use Corepack (via `packageManager`) to pin version.
2. **Lockfile required** — `pnpm-lock.yaml` always committed. Guarantees reproducible installs.
3. **Frozen lockfile in CI** — `pnpm install --frozen-lockfile` (or `npm ci`) fails if lockfile doesn't match `package.json`. Never `npm install` in CI.
4. **Corepack** — Use `packageManager` in `package.json` to pin exact package manager version. Avoids surprises across environments.
5. **One package manager per project** — Do not mix lockfiles. If pnpm, do not commit `package-lock.json`.

---

## 2. Minimum Versions

| Technology | Minimum Version                                    |
| ---------- | -------------------------------------------------- |
| Node.js    | 22+                                                |
| pnpm       | 11+                                                |
| npm        | 11+                                                |
| Corepack   | Bundled in Node 22-24; install via npm on Node 25+ |

---

## 3. package.json — Essential Fields

```json
{
  "name": "@mi-app/app",
  "version": "1.0.0",
  "private": true,
  "description": "Project description",
  "type": "module",
  "packageManager": "pnpm@11.20.0",
  "engines": {
    "node": ">=22",
    "pnpm": ">=11"
  },
  "devEngines": {
    "runtime": { "name": "node", "version": ">=22", "onFail": "error" }
  },
  "scripts": {
    "preinstall": "npx only-allow pnpm",
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint .",
    "test": "vitest run",
    "preview": "vite preview"
  },
  "exports": {
    ".": "./src/index.js",
    "./utils": "./src/utils.js"
  },
  "dependencies": {
    "react": "catalog:"
  }
}
```

### type: "module"

Enables ESM by default. All `.js` = ES modules. Use `.cjs` for CommonJS.

### overrides (pnpm 11+)

> In pnpm 11, overrides go in **`pnpm-workspace.yaml`**. The `pnpm.overrides` field in `package.json` is no longer read.

```yaml
# pnpm-workspace.yaml
overrides:
  react: "^18.3.1"
  "react-dom@18":
    react: "^18.3.1"
  "semver@<7.5.2": ">=7.5.2"
  "bar@^2.1.0": "3.0.0"
  quux: "npm:@myorg/quux@^1.0.0"
```

### exports map

```json
{
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    },
    "./utils": {
      "import": "./dist/utils.js",
      "require": "./dist/utils.cjs"
    },
    "./package.json": "./package.json"
  }
}
```

> With complete `exports`, Node/bundlers ignore `main`/`module`. `module` is legacy for old consumers — prefer `exports` alone for new packages.

---

## 4. pnpm Commands — Quick Reference

| Task             | Command                           |
| ---------------- | --------------------------------- |
| Install          | `pnpm install`                    |
| CI install       | `pnpm install --frozen-lockfile`  |
| Add prod dep     | `pnpm add <pkg>`                  |
| Add dev dep      | `pnpm add -D <pkg>`               |
| Add optional     | `pnpm add -O <pkg>`               |
| Specific version | `pnpm add eslint@10`              |
| Version range    | `pnpm add react@">=18 <19"`       |
| Exact version    | `pnpm add lodash-es --save-exact` |
| Remove           | `pnpm remove <pkg>`               |
| Update (range)   | `pnpm update`                     |
| Update latest    | `pnpm up -L`                      |
| Run script       | `pnpm <script>`                   |
| Run local bin    | `pnpm exec <bin>`                 |
| Run w/o install  | `pnpm dlx <pkg>`                  |
| Why installed    | `pnpm why <pkg>`                  |
| Dependency tree  | `pnpm list`                       |
| Audit            | `pnpm audit`                      |
| Outdated         | `pnpm outdated`                   |

> npm alternative: only 5-line diff table below. pnpm is default.

| Task            | npm (alternative)      |
| --------------- | ---------------------- |
| Install         | `npm install`          |
| CI install      | `npm ci`               |
| Add prod        | `npm install <pkg>`    |
| Add dev         | `npm install -D <pkg>` |
| Run script      | `npm run <script>`     |
| Run w/o install | `npx <pkg>`            |

---

## 5. Workspaces and Monorepos

### pnpm Workspaces

```yaml
# pnpm-workspace.yaml
packages:
  - "packages/*"
  - "apps/*"
  - "!**/test/**"
```

```bash
pnpm install                          # whole workspace
pnpm --filter @mi-app/server add express
pnpm -r build                         # build all packages
pnpm -r --parallel build              # parallel build
```

### Filtering (pnpm)

```bash
pnpm --filter @mi-app/app test                    # specific package
pnpm --filter "@mi-app/*" test                    # by pattern
pnpm --filter "{packages/*}" test                 # by glob
pnpm --filter ...@mi-app/app test                 # + dependencies
pnpm --filter @mi-app/app... test                 # + dependents
pnpm --filter "@mi-app/*{components/**}[origin/main]" test  # modified packages
```

### npm Workspaces (reference)

```json
{ "workspaces": ["packages/*", "apps/*"] }
```

```bash
npm install -w @mi-app/server express
npm run test --workspaces
npm run test --workspace=@mi-app/app
npm exec --ws -- eslint .
```

---

## 6. pnpm Catalogs

### Default catalog

```yaml
# pnpm-workspace.yaml
packages:
  - "packages/*"

catalog:
  react: ^18.3.1
  react-dom: ^18.3.1
  typescript: ^5.5.0
```

```json
{
  "dependencies": {
    "react": "catalog:",
    "react-dom": "catalog:"
  },
  "devDependencies": {
    "typescript": "catalog:"
  }
}
```

### Named catalogs (for migrations)

```yaml
# pnpm-workspace.yaml
catalog:
  react: ^16.14.0

catalogs:
  react17:
    react: ^17.0.2
    react-dom: ^17.0.2
  react18:
    react: ^18.2.0
    react-dom: ^18.2.0
```

```json
{
  "dependencies": {
    "react": "catalog:react18",
    "react-dom": "catalog:react18"
  }
}
```

---

## 7. Security

> Full security audit workflow in `security` skill. This section covers pnpm-specific hardening.

### allowBuilds (pnpm 11+)

Dependency postinstall scripts **do not run by default**; approve explicitly.

```yaml
# pnpm-workspace.yaml
allowBuilds:
  esbuild: true
  core-js: false
  "nx@21.6.4 || 21.6.5": true
```

```bash
pnpm approve-builds             # interactive
pnpm approve-builds --all       # non-interactive (CI)
```

### minimumReleaseAge (release cooldown)

Delays adoption of freshly published versions. Default **1440 minutes (1 day)** in pnpm 11.

```yaml
# pnpm-workspace.yaml
minimumReleaseAge: 1440
minimumReleaseAgeExclude:
  - webpack
```

### Overrides for vulnerabilities

```yaml
# pnpm-workspace.yaml
overrides:
  "semver@<7.5.2": ">=7.5.2"
  "braces@<3.0.3": ">=3.0.3"
```

> npm uses `overrides` in `package.json`. In pnpm 11 use `pnpm-workspace.yaml`.

### blockExoticSubdeps

`true` by default (pnpm 10.26+): only direct deps may come from exotic sources (git, tarballs).

### supportedArchitectures

```yaml
# pnpm-workspace.yaml
supportedArchitectures:
  os: [darwin, linux]
  cpu: [x64, arm64]
```

### Best practices

- Do not disable build scripts globally. In npm, `ignore-scripts` is temporary only; in pnpm 11+ scripts don't run by default — approve per package with `allowBuilds`
- `only-allow pnpm` — prevent npm/yarn installs
- Dependabot / Renovate — enable for automated security PRs
- `pnpm audit` in CI — fail on high+ vulnerabilities
- Review `npm fund` to understand funded projects

---

## 8. Publishing

```bash
# pnpm
pnpm publish                          # publish package
pnpm publish --access public          # scoped packages (@mi-app/)
pnpm publish --publish-branch main
pnpm -r publish                       # publish whole workspace

# Changesets (monorepos)
pnpm add -DW @changesets/cli
pnpm changeset init
pnpm changeset                        # create changeset
pnpm changeset version                # bump versions
pnpm changeset publish                # publish
```

### package.json for publishing

```json
{
  "name": "@mi-app/utils",
  "version": "1.0.0",
  "private": false,
  "publishConfig": { "access": "public" },
  "files": ["dist", "!dist/**/*.test.*"],
  "main": "./dist/index.js",
  "module": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    }
  },
  "sideEffects": false
}
```

> **Build before publish**: add `prepublishOnly`:
> `"prepublishOnly": "pnpm build"`.
> **pnpm deploy** (serverless): creates standalone dir with production
> `node_modules`:
>
> ```bash
> pnpm deploy --filter @mi-app/server dist/server
> ```
>
> For application publishing (not packages), see `deploy` skill.

---

## 9. CI/CD

> Full CI/CD workflow template in `deploy` skill. pnpm-specific rules:

- **Install with frozen lockfile** — `pnpm install --frozen-lockfile` (or `npm ci`); never plain `pnpm install` in CI.
- **Cache pnpm store** — `actions/setup-node` with `cache: "pnpm"`.
- **Speed up with `pnpm fetch`** — fill store from lockfile, then install from store:

```yaml
- uses: actions/setup-node@v7
  with:
    node-version: 24
    cache: "pnpm"

- run: pnpm fetch # fills store from lockfile
- run: pnpm install --offline # installs from store
- run: pnpm lint && pnpm test && pnpm build
```

---

## 10. Cache and Disk

### pnpm Store

```bash
pnpm store path                       # show store path
pnpm store status                     # verify integrity
pnpm store prune                      # clean up unused packages
pnpm store add express@4              # add specific to store
```

### Content-addressable storage

pnpm uses global store with content-addressable storage. Same file stored
once, referenced by hash. Saves space across projects.

---

## 11. Prohibitions

- ❌ DO NOT commit `node_modules/`
- ❌ DO NOT mix lockfiles (`pnpm-lock.yaml` + `package-lock.json`)
- ❌ DO NOT use `npm install` if project uses pnpm
- ❌ DO NOT use `npm install` in CI (use `npm ci` or `pnpm install --frozen-lockfile`)
- ❌ DO NOT use `--force` or `--legacy-peer-deps` as permanent solution
- ❌ DO NOT leave loose versions without range (`"react": "18.3.1"` without `^`) — reserve `--save-exact` for critical deps
- ❌ DO NOT disable `ignore-scripts` globally (only per package if necessary)
- ❌ DO NOT ignore vulnerabilities (`pnpm audit` / `npm audit` must pass in CI)
- ❌ DO NOT publish without prior build
- ❌ DO NOT delete lockfiles to "solve" problems
- ❌ DO NOT install global deps without explicit `--global`
- ❌ DO NOT use `npm link` in pnpm projects (use `pnpm link`)
- ❌ DO NOT modify `node_modules` manually

---

## 12. Methodology

Before using ANY package manager command/config/pattern not
documented in this skill:

1. **MCP Context7** (priority): `context7_resolve-library-id` +
   `context7_query-docs` for the specific tool.
2. **Official docs**: pnpm.io — verify current behavior + options.
3. **Project config**: `package.json`, `pnpm-workspace.yaml`, `.npmrc`
   — verify against actual setup.
4. **HARD RULE**: If not in this skill AND cannot be verified against
   2 authoritative sources → DO NOT USE IT. Document as assumption or risk in
   report to orchestrator.

---

## 13. References

> **Note:** For CI/CD workflow templates, see [Deploy](../deploy/SKILL.md)
> **Note:** For scripts in package.json, see [JavaScript](../javascript/SKILL.md)
> **Note:** For version control, see [Git](../git/SKILL.md)
> **Note:** For dependency security, see [Security](../security/SKILL.md)
> **Note:** For TypeScript tooling, see [TypeScript](../typescript/SKILL.md)

---

Last updated: 2026-08

