Advanced Features
Advanced cleanup, patch tracking, and override management workflows
Advanced cleanup, patch tracking, and override management workflows
Pastoralist supports npm's nested override syntax for overriding transitive dependencies (dependencies of dependencies).
When you need to override a transitive dependency, you can use nested overrides:
{
"dependencies": {
"pg": "^8.13.1"
},
"overrides": {
"pg": {
"pg-types": "^4.0.1"
}
}
}
This tells npm to use pg-types@^4.0.1 whenever it's required by the pg package, regardless of what version pg actually specifies.
You can override multiple transitive dependencies:
{
"overrides": {
"pg": {
"pg-types": "^4.0.1",
"pg-protocol": "^1.6.0"
},
"express": {
"cookie": "0.5.0"
}
}
}
Nested overrides are tracked with a special notation in the appendix. Each entry
still gets a ledger recording when it was added:
{
"pastoralist": {
"appendix": {
"pg-types@^4.0.1": {
"dependents": {
"my-app": "pg@^8.13.1 (nested override)"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"source": "manual"
}
},
"[email protected]": {
"dependents": {
"my-app": "express@^4.18.0 (nested override)"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"source": "manual"
}
}
}
}
}
In monorepos, nested overrides in workspace packages are also tracked. For example,
packages/app/package.json might contain:
{
"overrides": {
"pg": {
"pg-types": "^4.0.1"
}
}
}
Pastoralist will detect and manage these nested overrides across all workspace packages when using the --depPaths option.
Pastoralist automatically detects and tracks patches created by tools like patch-package.
When you have patches in your patches/ directory:
patches/
├── lodash+4.17.21.patch
├── express+4.18.0.patch
└── react+18.2.0.patch
Pastoralist will track them in the appendix:
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"my-app": "lodash@^4.17.0"
},
"patches": ["patches/lodash+4.17.21.patch"],
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"source": "manual"
}
}
}
}
}
When a dependency is removed, pastoralist alerts you:
🐑 Found 2 potentially unused patch files:
- patches/old-package+1.0.0.patch
- patches/removed-dep+2.0.0.patch
Consider removing these patches if the packages are no longer used.
Pastoralist considers peerDependencies when tracking override usage.
{
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0"
},
"overrides": {
"react": "18.2.0"
}
}
The appendix will reflect peer dependency requirements:
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"my-component": "react@^17.0.0 || ^18.0.0"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"source": "manual"
}
}
}
}
}
Pastoralist identifies overrides that are no longer needed and can remove them when you explicitly opt in.
--remove-unusedWhen a dependency is updated and no longer needs an override:
Before:
{
"dependencies": {
"lodash": "^4.17.0"
},
"overrides": {
"lodash": "4.17.21"
}
}
After updating lodash to 4.17.21 and running pastoralist --remove-unused:
{
"dependencies": {
"lodash": "^4.17.21"
},
"overrides": {}
}
When an override exists but no package in your project depends on it, Pastoralist labels it as (unused override) in the appendix:
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"root": "stale-pkg (unused override)"
}
}
}
}
}
Pastoralist displays a notice when unused overrides are detected:
| 1 unused override detected. Run with --remove-unused to clean up. |
To remove them, run with the --remove-unused flag:
pastoralist --remove-unused
This removes both the override from overrides and its entry from the appendix.
Set keep: true on a ledger entry to prevent --remove-unused from ever removing it:
{
"[email protected]": {
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"keep": true
}
}
}
For time- or version-bounded protection, use a KeepConstraint:
{
"[email protected]": {
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"keep": {
"reason": "Waiting for upstream patch",
"untilVersion": "4.18.0",
"until": "2027-06-01"
}
}
}
}
Once the condition is met, --remove-unused can treat the override as removable
again.
Pastoralist tracks overrides needed by transitive dependencies:
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"mkdirp": "minimist@^1.2.6",
"optimist": "minimist@~1.2.0"
}
}
}
}
}
Pastoralist uses version-range matching to determine if overrides are needed.
Given these dependencies:
{
"dependencies": {
"express": "^4.18.0"
}
}
And this override:
{
"overrides": {
"express": "4.18.2"
}
}
Pastoralist understands that ^4.18.0 could resolve to 4.18.2 naturally, so the override might not be necessary unless it's fixing a specific issue.
Pastoralist keeps appendix entries while an override is still tracked. When you
run with --remove-unused, it removes both the override and the matching
appendix entry.
--remove-unused removes the override and appendix entryUse ledger reason and keep fields for override decisions that should stay
reviewable until a specific cleanup condition is met.
Pastoralist reads the override field your package manager already uses:
overridespnpm.overridesresolutionsWhen it writes changes, it preserves the existing override field when one is present. If a security fix creates the first override field in a project, Pastoralist chooses the field that matches the detected package manager.
Yarn resolutions:
{
"resolutions": {
"package-a": "1.0.0",
"**/package-b": "2.0.0"
}
}
The equivalent npm or Bun override shape:
{
"overrides": {
"package-a": "1.0.0",
"package-b": "2.0.0"
}
}
Debug mode (--debug) provides detailed information:
🐑 pastoralist checking herd...
[DEBUG] Reading package.json from /path/to/package.json
[DEBUG] Found 3 overrides
[DEBUG] Analyzing dependency tree...
[DEBUG] [email protected] required by:
- [email protected] (wants lodash@^4.17.0)
- [email protected] (wants lodash@~4.17.0)
[DEBUG] Writing updated package.json
✅ pastoralist the herd is safe!
Pastoralist complements patch-package by tracking which overrides have associated patches:
# Apply a patch
npx patch-package lodash
# Run pastoralist to update tracking
npx pastoralist
Use with npm-check-updates to manage both regular updates and overrides:
# Update dependencies
npx npm-check-updates -u
# Update override tracking
npx pastoralist
Configure automated tools to run pastoralist after updates:
{
"postUpgradeTasks": {
"commands": ["npm install", "npx pastoralist"],
"fileFilters": ["package.json"]
}
}
Create policies for when overrides should be used:
// scripts/check-override-policy.js
const pkg = require("./package.json");
const policies = {
security: ["minimist", "lodash"], // Require review before keeping security overrides
compatibility: ["react"], // Track compatibility overrides
temporary: ["experimental-pkg"], // Review temporary overrides regularly
};
// Validate overrides match policies
Object.keys(pkg.overrides || {}).forEach((override) => {
const category = Object.entries(policies).find(([_, pkgs]) => pkgs.includes(override))?.[0];
if (!category) {
console.warn(`Override '${override}' has no policy!`);
}
});
Extract insights from the appendix:
const pkg = require("./package.json");
const appendix = pkg.pastoralist?.appendix || {};
// Find overrides with most dependents
const overrideImpact = Object.entries(appendix)
.map(([override, info]) => ({
override,
dependentCount: Object.keys(info.dependents || {}).length,
}))
.sort((a, b) => b.dependentCount - a.dependentCount);
console.log("Highest impact overrides:", overrideImpact.slice(0, 5));
{
"dependencies": {
"pg": "^8.13.1"
},
"overrides": {
"pg": {
"pg-types": "^4.0.1"
}
}
}
{
"overrides": {
"pg": {
"pg-types": "^4.0.1",
"pg-protocol": "^1.6.0"
},
"express": {
"cookie": "0.5.0"
}
}
}
{
"pastoralist": {
"appendix": {
"pg-types@^4.0.1": {
"dependents": {
"my-app": "pg@^8.13.1 (nested override)"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"source": "manual"
}
},
"[email protected]": {
"dependents": {
"my-app": "express@^4.18.0 (nested override)"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"source": "manual"
}
}
}
}
}
{
"overrides": {
"pg": {
"pg-types": "^4.0.1"
}
}
}
patches/
├── lodash+4.17.21.patch
├── express+4.18.0.patch
└── react+18.2.0.patch
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"my-app": "lodash@^4.17.0"
},
"patches": ["patches/lodash+4.17.21.patch"],
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"source": "manual"
}
}
}
}
}
🐑 Found 2 potentially unused patch files:
- patches/old-package+1.0.0.patch
- patches/removed-dep+2.0.0.patch
Consider removing these patches if the packages are no longer used.
{
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0"
},
"overrides": {
"react": "18.2.0"
}
}
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"my-component": "react@^17.0.0 || ^18.0.0"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"source": "manual"
}
}
}
}
}
{
"dependencies": {
"lodash": "^4.17.0"
},
"overrides": {
"lodash": "4.17.21"
}
}
{
"dependencies": {
"lodash": "^4.17.21"
},
"overrides": {}
}
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"root": "stale-pkg (unused override)"
}
}
}
}
}
| 1 unused override detected. Run with --remove-unused to clean up. |
pastoralist --remove-unused
{
"[email protected]": {
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"keep": true
}
}
}
{
"[email protected]": {
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"keep": {
"reason": "Waiting for upstream patch",
"untilVersion": "4.18.0",
"until": "2027-06-01"
}
}
}
}
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"mkdirp": "minimist@^1.2.6",
"optimist": "minimist@~1.2.0"
}
}
}
}
}
{
"dependencies": {
"express": "^4.18.0"
}
}
{
"overrides": {
"express": "4.18.2"
}
}
{
"resolutions": {
"package-a": "1.0.0",
"**/package-b": "2.0.0"
}
}
{
"overrides": {
"package-a": "1.0.0",
"package-b": "2.0.0"
}
}
🐑 pastoralist checking herd...
[DEBUG] Reading package.json from /path/to/package.json
[DEBUG] Found 3 overrides
[DEBUG] Analyzing dependency tree...
[DEBUG] [email protected] required by:
- [email protected] (wants lodash@^4.17.0)
- [email protected] (wants lodash@~4.17.0)
[DEBUG] Writing updated package.json
✅ pastoralist the herd is safe!
# Apply a patch
npx patch-package lodash
# Run pastoralist to update tracking
npx pastoralist
# Update dependencies
npx npm-check-updates -u
# Update override tracking
npx pastoralist
{
"postUpgradeTasks": {
"commands": ["npm install", "npx pastoralist"],
"fileFilters": ["package.json"]
}
}
// scripts/check-override-policy.js
const pkg = require("./package.json");
const policies = {
security: ["minimist", "lodash"], // Require review before keeping security overrides
compatibility: ["react"], // Track compatibility overrides
temporary: ["experimental-pkg"], // Review temporary overrides regularly
};
// Validate overrides match policies
Object.keys(pkg.overrides || {}).forEach((override) => {
const category = Object.entries(policies).find(([_, pkgs]) => pkgs.includes(override))?.[0];
if (!category) {
console.warn(`Override '${override}' has no policy!`);
}
});
const pkg = require("./package.json");
const appendix = pkg.pastoralist?.appendix || {};
// Find overrides with most dependents
const overrideImpact = Object.entries(appendix)
.map(([override, info]) => ({
override,
dependentCount: Object.keys(info.dependents || {}).length,
}))
.sort((a, b) => b.dependentCount - a.dependentCount);
console.log("Highest impact overrides:", overrideImpact.slice(0, 5));