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.
Open in StackBlitz

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": {}
}
Open in StackBlitz

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

  1. Initial state: Override with appendix
  2. Dependency removed: Pastoralist reports the override as unused
  3. Cleanup run: --remove-unused removes 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

  1. Regular Updates: Run pastoralist on install, scheduled CI, or dependency-update PRs
  2. Review Patches: Check for upstream fixes when dependencies update

Copyright © 2026 - All rights reserved

Pastoralist Logo