A tool to watch over node module resolutions and overrides 🐑 👩🏽🌾
npm install pastoralist
!ci

Pastoralist helps you maintain node module overrides and address security issues in dependencies.
1. Pastoralist tracks, secures, and cleans up your overrides, resolutions, and patches.
2. Pastoralist can help resolve dependency security alerts by creating overrides for vulnerable packages.
---
One command. Three features.
``bash`
npm i pastoralist -D && pastoralist --init
- Tracks why each override exists
- Scans for security vulnerabilities
- Removes unused overrides
---
- What are overrides and resolutions?
- The Problem
- The Solution
- What Pastoralist Automates
- How Pastoralist Works
- Key Notes
- Workspaces and Monorepos
- Configuration
- Configuration Files
- Configuration Priority
- Configuration Options
- Security Tracking
- Best Practices
- Setup
- Additional Commands
- Thanks
---
Package manager overrides and resolutions let you control exact dependency versions in your node_modules.
Package managers (npm, yarn, pnpm, bun) use these overrides to fix:
- Security vulnerabilities in nested dependencies
- Bugs in transitive dependencies
- Version conflicts
Read more: npm overrides, yarn resolutions, pnpm overrides, bun overrides
---
You add overrides to fix a security alert or broken dependency:
`js`
"overrides": {
"lodash": "4.17.21" // Why? What for? No idea anymore.
}
Six months later, you have no clue:
`mermaid
flowchart LR
You[You] --> Question1{Why is this here?}
Question1 --> Question2{What uses it?}
Question2 --> Question3{Still needed?}
Question3 --> Stuck[🤷 Just leave it...]
style You fill:#e3f2fd
style Stuck fill:#ffebee
`
You end up with ghost overrides haunting your package.json forever.
---
Pastoralist automatically documents every override:
`js`
"overrides": {
"trim": "^0.0.3"
},
"pastoralist": {
"appendix": {
"trim@^0.0.3": {
"dependents": {
"remark-parse": "4.0.0" // ← Ah! remark-parse needs this
}
}
}
}
No more mysteries. Every override is tracked.
`mermaid
flowchart LR
Install[npm install] --> Auto[Pastoralist runs]
Auto --> Track[Tracks deps]
Auto --> Scan[Scans security]
Auto --> Clean[Cleans unused]
Track --> Done[✓ Done]
Scan --> Done
Clean --> Done
style Install fill:#e3f2fd
style Auto fill:#f3e5f5
style Done fill:#e8f5e9
`
Automatic cleanup:
When trim is no longer needed, Pastoralist removes it automatically:
`js`
"overrides": {}, // ← Cleaned up automatically
"pastoralist": {
"appendix": {} // ← Cleaned up automatically
}
Automatic security checks:
Run once with --checkSecurity enabled:
`js`
"pastoralist": {
"security": {
"enabled": true,
"provider": "osv"
}
}
Pastoralist tracks the fix:
`js`
"overrides": {
"lodash": "4.17.21" // ← Auto-fixed CVE-2021-23337
},
"pastoralist": {
"appendix": {
"lodash@4.17.21": {
"dependents": {"my-app": "lodash@^4.17.0"},
"ledger": {
"reason": "Security vulnerability CVE-2021-23337",
"securityProvider": "osv"
}
}
}
}
Security fixes are tracked with full context.
---
Pastoralist documents every override, including nested dependencies.
`js`
"overrides": {
"pg": {
"pg-types": "^4.0.1" // Nested override
}
}
`mermaid
flowchart TD
Start([Nested override detected]) --> Parse[Parse parent dependency]
Parse --> Track[Track in appendix]
Track --> End([Full dependency chain visible])
style Start fill:#e3f2fd
style End fill:#e8f5e9
style Parse fill:#f3e5f5
`
Result:
`js`
"pastoralist": {
"appendix": {
"pg-types@^4.0.1": {
"dependents": {
"my-app": "pg@^8.13.1 (nested override)"
}
}
}
}
Enable security scanning with your preferred provider.
`js`
"pastoralist": {
"security": {
"enabled": true,
"provider": "osv",
"severityThreshold": "medium"
}
}
`mermaid
flowchart TD
Start([npm install]) --> Scan[Request vulnerability reports]
Scan --> Detect{Vulnerabilities found?}
Detect -->|Yes| Fix[Auto-generate override]
Detect -->|No| Done[✓ Done]
Fix --> Done
style Start fill:#e3f2fd
style Fix fill:#fff3cd
style Done fill:#e8f5e9
`
Supported providers:
- OSV (default) - No auth required
- GitHub - Requires token and permissions (see below)
- Snyk [EXPERIMENTAL] - Requires CLI and token
- Socket [EXPERIMENTAL] - Requires CLI and token
#### GitHub Provider Setup
When using the GitHub provider in CI workflows, add the vulnerability-alerts: read permission:
`yaml`
permissions:
contents: write
vulnerability-alerts: read
You must also enable Dependabot alerts in your repository: Settings > Code security and analysis > Dependabot alerts.
If permissions are insufficient, Pastoralist will warn and continue (your workflow won't fail).
When dependencies are removed, Pastoralist removes their overrides.
`mermaid
flowchart TD
Start([Dependency removed or updated]) --> Check[Check if override still needed]
Check --> Remove[Auto-remove from overrides & appendix]
Remove --> Done[✓ Cleaned up]
style Start fill:#e3f2fd
style Remove fill:#f3e5f5
style Done fill:#e8f5e9
`
Works with patch-package. Links patches to overrides and warns about unused patches.
`js`
"pastoralist": {
"appendix": {
"lodash@4.17.21": {
"dependents": {"my-app": "lodash@^4.17.0"},
"patches": ["patches/lodash+4.17.21.patch"] // ← Auto-tracked
}
}
}
---
You: Add an override when needed.
Pastoralist: Tracks, scans, and cleans up.
`mermaid
flowchart LR
You[You add override] --> Install[npm install]
Install --> Pastor[Pastoralist runs]
Pastor --> Track[Tracks it]
Pastor --> Scan[Scans it]
Pastor --> Clean[Cleans if unused]
Track --> Chill[Back to coding]
Scan --> Chill
Clean --> Chill
style You fill:#e3f2fd
style Pastor fill:#f3e5f5
style Chill fill:#e8f5e9
`
Add it to your postinstall script and forget about it:
`js`
"scripts": {
"postinstall": "pastoralist"
}
For detailed architecture, code flows, and user journeys, see Architecture and User Journeys
- You control what goes into overrides/resolutions
- Pastoralist handles tracking, security, and cleanup
- Runs on every install via postinstall hook
Pastoralist provides enhanced support for monorepo scenarios where overrides are defined at the root but dependencies exist in workspace packages.
#### Auto-Detection
If your package.json has a workspaces field, Pastoralist automatically scans workspace packages:
`json`
{
"workspaces": ["packages/", "apps/"],
"overrides": {
"lodash": "4.17.21"
}
}
Run pastoralist and it automatically scans all workspace packages. No configuration needed.
#### Manual Configuration
For explicit control, configure workspace scanning:
`json`
{
"pastoralist": {
"depPaths": "workspace"
}
}
Or specify custom paths:
`json`
{
"pastoralist": {
"depPaths": ["packages//package.json", "apps//package.json"]
}
}
#### Monorepo Override Tracking
When you have overrides at the root for packages only installed in workspace packages, Pastoralist tracks them properly:
`js`
// Root package.json with overrides for workspace packages
{
"overrides": {
"lodash": "4.17.21" // Used by workspace packages, not root
},
"pastoralist": {
"overridePaths": {
"packages/app-a/package.json": {
"lodash@4.17.21": {
"dependents": {
"app-a": "lodash@^4.17.0"
}
}
}
}
}
}
#### Configuration Options
1. Interactive Configuration - Let Pastoralist guide you through setup:
`bashInitialize with interactive prompts
pastoralist --init
When Pastoralist detects overrides for packages not in root dependencies, it will:
- Prompt you to configure workspace paths
- Offer to auto-detect common monorepo structures
- Allow you to specify custom paths
- Optionally save the configuration to your package.json
2. Using depPaths CLI Flag - Specify paths to scan for package.json files:
`bash
pastoralist --depPaths "packages//package.json" "apps//package.json"
`3. Using depPaths in package.json - Configure dependency paths directly in your package.json:
`js
"pastoralist": {
"depPaths": "workspace" // Automatically uses all workspaces
}// OR specify custom paths
"pastoralist": {
"depPaths": ["packages//package.json", "apps//package.json"]
}
`When using
depPaths: "workspace", Pastoralist will automatically scan all packages defined in your workspaces field. This is the recommended approach for most monorepos as it keeps your configuration in sync with your workspace structure.Benefits of using
depPaths configuration:- Single source of truth in package.json
- No need to remember CLI flags
- Works automatically with postinstall scripts
- Appendix only appears in root package.json (workspace packages remain clean)
4. Using overridePaths/resolutionPaths - Configure in your package.json:
`js
"pastoralist": {
"overridePaths": { // or "resolutionPaths" for yarn
"packages/app-a/package.json": { / appendix for app-a / },
"packages/app-b/package.json": { / appendix for app-b / }
}
}
`This configuration ensures that:
- Overrides for packages not in root dependencies are preserved
- Each workspace package's usage is tracked separately
- The appendix correctly maps overrides to their actual consumers
---
Configuration
Pastoralist supports multiple configuration methods to fit your project's needs. Configuration can be defined in external files or directly in your
package.json.$3
Pastoralist searches for configuration files in this order (first found wins):
1.
.pastoralistrc (JSON format)
2. .pastoralistrc.json
3. pastoralist.json
4. pastoralist.config.js
5. pastoralist.config.tsExample
.pastoralistrc.json:`json
{
"checkSecurity": true,
"depPaths": "workspaces",
"security": {
"provider": "osv",
"severityThreshold": "medium"
}
}
`Example
pastoralist.config.js:`js
module.exports = {
checkSecurity: true,
depPaths: ["packages//package.json", "apps//package.json"],
security: {
provider: "osv",
severityThreshold: "high",
excludePackages: ["@types/*"],
},
};
`Example
pastoralist.config.ts:`ts
import { PastoralistConfig } from "pastoralist";const config: PastoralistConfig = {
checkSecurity: true,
depPaths: "workspaces",
security: {
provider: "osv",
severityThreshold: "critical",
},
};
export default config;
`$3
When both external config files and
package.json configuration exist:1. External config provides base settings
2.
package.json overrides top-level fields
3. Nested objects (like security) are deep mergedExample:
`js
// .pastoralistrc.json
{
"checkSecurity": true,
"depPaths": "workspaces",
"security": {
"provider": "osv",
"severityThreshold": "medium"
}
}// package.json
{
"pastoralist": {
"security": {
"severityThreshold": "high" // Overrides "medium" from .pastoralistrc.json
}
}
}
// Effective config:
{
"checkSecurity": true,
"depPaths": "workspaces",
"security": {
"provider": "osv",
"severityThreshold": "high" // From package.json
}
}
`$3
| Option | Type | Description |
| ----------------- | --------------------------------------------- | ----------------------------------------------------------- |
|
checkSecurity | boolean | Enable security vulnerability scanning |
| depPaths | "workspace" \| "workspaces" \| string[] | Paths to scan for dependencies in monorepos |
| appendix | object | Auto-generated dependency tracking (managed by Pastoralist) |
| overridePaths | object | Manual override tracking for specific paths |
| resolutionPaths | object | Manual resolution tracking for specific paths |
| security | object | Security scanning configuration (see below) |#### Security Configuration
| Option | Type | Description |
| ---------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
enabled | boolean | Enable/disable security checks |
| provider | "osv" \| "github" \| "snyk" \| "socket" | Security provider: osv (free, recommended), github (requires token, includes transitive deps), snyk [EXPERIMENTAL], socket [EXPERIMENTAL] |
| autoFix | boolean | Automatically apply security fixes |
| interactive | boolean | Use interactive mode for security fixes |
| securityProviderToken | string | API token for providers that require auth |
| severityThreshold | "low" \| "medium" \| "high" \| "critical" | Minimum severity level to report |
| excludePackages | string[] | Packages to exclude from security checks |
| hasWorkspaceSecurityChecks | boolean | Include workspace packages in scans |$3
When security vulnerabilities are detected and fixed, Pastoralist tracks complete vulnerability information in the appendix ledger:
`js
"pastoralist": {
"appendix": {
"lodash@4.17.21": {
"dependents": {
"my-app": "lodash@^4.17.0"
},
"ledger": {
"addedDate": "2024-01-15T10:30:00.000Z",
"reason": "Security vulnerability CVE-2021-23337",
"securityChecked": true,
"securityCheckDate": "2024-01-15T10:30:00.000Z",
"securityProvider": "osv",
"cve": "CVE-2021-23337",
"severity": "high",
"description": "Command injection in lodash",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-23337"
}
}
}
}
`The ledger tracks:
-
addedDate: When the override was first added
- reason: Why the override was needed
- securityChecked: Whether a security check was performed
- securityCheckDate: When the last security check occurred
- securityProvider: Which provider detected the vulnerability
- cve: CVE identifier (if applicable)
- severity: Vulnerability severity level (low, medium, high, critical)
- description: Brief description of the vulnerability
- url: Link to full vulnerability detailsThis complete audit trail lets you understand exactly which security issues were fixed and provides full context for future reference.
$3
1. Use external config files for shared settings across teams
2. Use
package.json for project-specific overrides
3. Commit config files to version control
4. Use depPaths: "workspaces" for most monorepos
5. Enable security checks in CI/CD pipelines with --checkSecurity---
Setup
> #### Okay! Hopefully the breakdowns above were clear enough on why you might want to use Pastoralist!
Please submit a pull request or issue if it wasn't!
Now for the super simple setup!
1. Install
`bash
npm install pastoralist --save-dev
pastoralist does not expect to be a dependency! It's a tool!!!
`2. run
`bash
pastoralist
=> That's it! Check out your package.json
`3. (recommended) add Pastoralist to a postInstall script
`js
// package.json
{
"scripts": {
"postinstall": "pastoralist"
}
}
`$3
Preview changes without writing to package.json:
`bash
pastoralist --dry-run
`This shows exactly what Pastoralist would change without modifying any files.
Quiet mode for CI:
`bash
pastoralist --quiet --checkSecurity
`Minimal output for CI pipelines. Exits with code 1 if vulnerabilities found, 0 if clean.
Show summary metrics:
`bash
pastoralist --summary
`Displays metrics table with packages scanned, vulnerabilities blocked, and overrides managed.
Add postinstall hook:
`bash
pastoralist --setup-hook
`Adds
pastoralist to your postinstall script automatically.Set up automated CI/CD security checks:
`bash
pastoralist setup-ci
`This generates a GitHub Actions workflow that:
- Runs on pull requests and pushes to main/master
- Runs weekly security scans
- Auto-detects your package manager (npm, yarn, pnpm, bun)
- Fails if package.json changes are uncommitted
- Comments on PRs when changes are needed
The workflow file is created at
.github/workflows/pastoralist.yml. Commit it to enable automated security checks in CI.---
GitHub Action
Pastoralist provides a GitHub Action for CI/CD integration.
$3
`yaml
name: Override Check
on: [pull_request]jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: yowainwright/pastoralist@v1
with:
mode: check
fail-on-security: true
`$3
`yaml
name: Override Maintenance
on:
schedule:
- cron: "0 0 1" # Weekly on Mondayjobs:
maintain:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: yowainwright/pastoralist@v1
with:
mode: pr
check-security: true
fail-on-security: true
pr-title: "chore(deps): update dependency overrides"
`$3
| Mode | Description |
| -------- | ------------------------------------------------------ |
|
check | Validate only - reports issues without modifying files |
| update | Modify package.json (default) - you handle commits |
| pr` | Create pull request with changes |See ACTION.md for full documentation including all inputs, outputs, and examples.
---
Shout out to Bryant Cabrera and the infamous Mardin for all the fun conversation, insights, and pairing around this topic.
---
Made by @yowainwright for fun with passion! O'Sassy, 2022