Advanced Features
Advanced cleanup, patch tracking, and override management workflows
Nested Overrides (Transitive Dependencies)
Pastoralist supports npm's nested override syntax for overriding transitive dependencies (dependencies of dependencies).
How It Works
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.
Multiple Nested Overrides
You can override multiple transitive dependencies:
{
"overrides": {
"pg": {
"pg-types": "^4.0.1",
"pg-protocol": "^1.6.0"
},
"express": {
"cookie": "0.5.0"
}
}
}
Tracking in Appendix
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"
}
}
}
}
}
Workspace Support
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.
Patch Support
Pastoralist automatically detects and tracks patches created by tools like patch-package.
How It Works
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"
}
}
}
}
}
Unused Patch Detection
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.
PeerDependencies Support
Pastoralist considers peerDependencies when tracking override usage.
Example
{
"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"
}
}
}
}
}
Smart Cleanup
Pastoralist identifies overrides that are no longer needed and can remove them when you explicitly opt in.
Removal with --remove-unused
When 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": {}
}
Unused Override Detection
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.
Protecting Overrides from Removal
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.
Transitive Dependency Tracking
Pastoralist tracks overrides needed by transitive dependencies:
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"mkdirp": "minimist@^1.2.6",
"optimist": "minimist@~1.2.0"
}
}
}
}
}
Fuzzy Version Matching
Pastoralist uses version-range matching to determine if overrides are needed.
How It Works
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.
Appendix Cleanup
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.
Example Scenario
- Initial state: Override with appendix
- Dependency removed: Pastoralist reports the override as unused
- Cleanup run:
--remove-unusedremoves the override and appendix entry
Use ledger reason and keep fields for override decisions that should stay
reviewable until a specific cleanup condition is met.
Multi-Format Support
Pastoralist reads the override field your package manager already uses:
- npm and Bun:
overrides - pnpm:
pnpm.overrides - Yarn:
resolutions
When 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.
Format Example
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 Insights
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!
Integration with Other Tools
patch-package
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
npm-check-updates
Use with npm-check-updates to manage both regular updates and overrides:
# Update dependencies
npx npm-check-updates -u
# Update override tracking
npx pastoralist
Renovate/Dependabot
Configure automated tools to run pastoralist after updates:
{
"postUpgradeTasks": {
"commands": ["npm install", "npx pastoralist"],
"fileFilters": ["package.json"]
}
}
Custom Workflows
Override Policies
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!`);
}
});
Appendix Analysis
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));
Best Practices
- Regular Updates: Run pastoralist on install, scheduled CI, or dependency-update PRs
- Review Patches: Check for upstream fixes when dependencies update