Package Manager — Rules and Conventions
1. Philosophy
- pnpm by default — Faster, disk-efficient, strict with dependencies. Use Corepack (via
packageManager) to pin version. - Lockfile required —
pnpm-lock.yamlalways committed. Guarantees reproducible installs. - Frozen lockfile in CI —
pnpm install --frozen-lockfile(ornpm ci) fails if lockfile doesn't matchpackage.json. Nevernpm installin CI. - Corepack — Use
packageManagerinpackage.jsonto pin exact package manager version. Avoids surprises across environments. - 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
{
"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. Thepnpm.overridesfield inpackage.jsonis no longer read.
# 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
{
"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 ignoremain/module.moduleis legacy for old consumers — preferexportsalone 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
# pnpm-workspace.yaml
packages:
- "packages/*"
- "apps/*"
- "!**/test/**"
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)
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)
{ "workspaces": ["packages/*", "apps/*"] }
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
# pnpm-workspace.yaml
packages:
- "packages/*"
catalog:
react: ^18.3.1
react-dom: ^18.3.1
typescript: ^5.5.0
{
"dependencies": {
"react": "catalog:",
"react-dom": "catalog:"
},
"devDependencies": {
"typescript": "catalog:"
}
}
Named catalogs (for migrations)
# 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
{
"dependencies": {
"react": "catalog:react18",
"react-dom": "catalog:react18"
}
}
7. Security
Full security audit workflow in
securityskill. This section covers pnpm-specific hardening.
allowBuilds (pnpm 11+)
Dependency postinstall scripts do not run by default; approve explicitly.
# pnpm-workspace.yaml
allowBuilds:
esbuild: true
core-js: false
"nx@21.6.4 || 21.6.5": true
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.
# pnpm-workspace.yaml
minimumReleaseAge: 1440
minimumReleaseAgeExclude:
- webpack
Overrides for vulnerabilities
# pnpm-workspace.yaml
overrides:
"semver@<7.5.2": ">=7.5.2"
"braces@<3.0.3": ">=3.0.3"
npm uses
overridesinpackage.json. In pnpm 11 usepnpm-workspace.yaml.
blockExoticSubdeps
true by default (pnpm 10.26+): only direct deps may come from exotic sources (git, tarballs).
supportedArchitectures
# pnpm-workspace.yaml
supportedArchitectures:
os: [darwin, linux]
cpu: [x64, arm64]
Best practices
- Do not disable build scripts globally. In npm,
ignore-scriptsis temporary only; in pnpm 11+ scripts don't run by default — approve per package withallowBuilds only-allow pnpm— prevent npm/yarn installs- Dependabot / Renovate — enable for automated security PRs
pnpm auditin CI — fail on high+ vulnerabilities- Review
npm fundto understand funded projects
8. Publishing
# 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
{
"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 productionnode_modules:pnpm deploy --filter @mi-app/server dist/serverFor application publishing (not packages), see
deployskill.
9. CI/CD
Full CI/CD workflow template in
deployskill. pnpm-specific rules:
- Install with frozen lockfile —
pnpm install --frozen-lockfile(ornpm ci); never plainpnpm installin CI. - Cache pnpm store —
actions/setup-nodewithcache: "pnpm". - Speed up with
pnpm fetch— fill store from lockfile, then install from store:
- 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
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 installif project uses pnpm - ❌ DO NOT use
npm installin CI (usenpm ciorpnpm install --frozen-lockfile) - ❌ DO NOT use
--forceor--legacy-peer-depsas permanent solution - ❌ DO NOT leave loose versions without range (
"react": "18.3.1"without^) — reserve--save-exactfor critical deps - ❌ DO NOT disable
ignore-scriptsglobally (only per package if necessary) - ❌ DO NOT ignore vulnerabilities (
pnpm audit/npm auditmust 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 linkin pnpm projects (usepnpm link) - ❌ DO NOT modify
node_modulesmanually
12. Methodology
Before using ANY package manager command/config/pattern not documented in this skill:
- MCP Context7 (priority):
context7_resolve-library-id+context7_query-docsfor the specific tool. - Official docs: pnpm.io — verify current behavior + options.
- Project config:
package.json,pnpm-workspace.yaml,.npmrc— verify against actual setup. - 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 Note: For scripts in package.json, see JavaScript Note: For version control, see Git Note: For dependency security, see Security Note: For TypeScript tooling, see TypeScript
Last updated: 2026-08