Configuration
Configure Pastoralist with package.json, rc files, or JavaScript config files
Configure Pastoralist with package.json, rc files, or JavaScript config files
For most projects, start small: enable workspace scanning only if you have workspaces, and enable security checks only where you want advisory data.
Pastoralist searches for configuration files in this order (first found wins):
.pastoralistrc (JSON format).pastoralistrc.jsonpastoralist.jsonpastoralist.config.cjspastoralist.config.jspastoralist.config.mjsAll external config files use the same top-level Pastoralist settings. Choose the filename by format and convention:
.pastoralistrc: extensionless rc file parsed as JSON.pastoralistrc.json: explicit JSON rc file, and the JSON option created by
pastoralist initpastoralist.json: visible non-dotfile JSON configpastoralist.config.cjs: CommonJS module with module.exportspastoralist.config.js: JavaScript config. CommonJS exports are accepted;
otherwise it is imported as a modulepastoralist.config.mjs: ESM module with export defaultUse pastoralist.json, not .pastoralist.json.
Enable security checks with defaults:
{
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv"
}
}
.pastoralistrc.json{
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv",
"severityThreshold": "medium"
}
}
pastoralist.config.jsmodule.exports = {
depPaths: ["packages/*/package.json", "apps/*/package.json"],
checkSecurity: true,
security: {
provider: "osv",
severityThreshold: "high",
excludePackages: ["@types/*"],
},
};
pastoralist.config.mjsexport default {
checkSecurity: true,
depPaths: "workspace",
security: {
provider: "osv",
severityThreshold: "critical",
},
};
When both external config files and package.json configuration exist, they are merged with package.json taking precedence:
package.json overrides top-level fieldssecurity) are deep merged.pastoralistrc.json:
{
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv",
"severityThreshold": "medium"
}
}
package.json:
{
"pastoralist": {
"security": {
"severityThreshold": "high"
}
}
}
Effective configuration:
{
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv",
"severityThreshold": "high"
}
}
| Option | Type | Description |
|---|---|---|
checkSecurity | boolean | Enable security vulnerability scanning |
compactAppendix | boolean | Collapse routine appendix entries to { addedDate }; entries with security info, patches, or active keep constraints stay expanded |
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 |
bestCase | object | Opt-in dependency-portfolio optimization policy |
security | object | Security scanning configuration |
The security object supports the following options:
| Option | Type | Description |
|---|---|---|
enabled | boolean | Enable/disable security checks |
provider | "osv" | "github" | "snyk" | "npm" | "socket" | "spektion" | array | Security provider or providers to use |
autoFix | boolean | Automatically apply security fixes |
interactive | boolean | Use interactive mode for security fixes |
securityProviderToken | string | API token for providers that require authentication. Prefer provider environment variables; use this only for controlled config that will not be committed. |
severityThreshold | "low" | "medium" | "high" | "critical" | Minimum severity level to report |
excludePackages | string[] | Packages to exclude from security checks |
hasWorkspaceSecurityChecks | boolean | Include workspace packages in security scans |
strict | boolean | Fail when a security provider cannot complete |
Enable bestCase when package fixes must be chosen as one portfolio instead
of independently. Pastoralist evaluates complete version combinations so a fix
for one package cannot hide a vulnerability introduced elsewhere.
{
"pastoralist": {
"checkSecurity": true,
"bestCase": {
"enabled": true,
"userOwnedOverrides": ["alpha"],
"riskAggregation": "both",
"objectives": [
"known-exploited",
"critical",
"high",
"expected-exploitation",
"package-exposures",
"compatibility",
"change-count",
"oldness"
],
"search": {
"mode": "auto",
"exactStateLimit": 256,
"beamWidth": 16,
"maxEvaluations": 1000
}
}
}
}
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable portfolio selection during security checks |
userOwnedOverrides | string[] | [] | Hard-constrain listed packages to their active override version |
riskAggregation | "unique-cves" | "package-exposures" | "both" | "both" | Choose how vulnerability risk is counted |
objectives | BestCaseObjective[] | See above | Set the lexicographic ranking order |
search.mode | "auto" | "exact" | "beam" | "auto" | Select exhaustive or deterministic bounded search |
search.exactStateLimit | positive integer | 256 | Limit exact search to this many states in auto mode |
search.beamWidth | positive integer | 16 | Retain this many states at each step during beam search |
search.maxEvaluations | positive integer | 1000 | Stop after this many complete-state evaluations |
Objectives are compared in array order; Pastoralist does not combine them
into a weighted sum. Supported objectives are known-exploited, critical,
high, medium, low, expected-exploitation, package-exposures,
compatibility, change-count, and oldness.
An exact search reports provenOptimal: true only when it evaluates every
state. Beam search and capped exact search report provenOptimal: false.
You can configure Pastoralist directly in your package.json:
{
"name": "my-project",
"version": "1.0.0",
"pastoralist": {
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv",
"severityThreshold": "medium",
"excludePackages": ["@types/*"]
}
}
}
For monorepos, use depPaths to specify which package.json files to scan:
The simplest approach for monorepos with a workspaces field:
{
"workspaces": ["packages/*", "apps/*"],
"pastoralist": {
"depPaths": "workspace"
}
}
This automatically scans all workspace packages defined in your workspaces field.
"workspaces" is accepted as an alias.
For more control, specify custom glob patterns:
{
"pastoralist": {
"depPaths": ["packages/*/package.json", "apps/*/package.json"]
}
}
Every appendix entry gets a ledger with at least addedDate. When a security
provider detects a fix, Pastoralist adds CVE, severity, provider, and
vulnerable-range metadata to the same ledger:
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"my-app": "lodash@^4.17.0"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"reason": "Security vulnerability CVE-2021-23337",
"source": "security",
"securityChecked": true,
"securityCheckDate": "2026-05-30T00:00:00.000Z",
"securityCheckResult": "clean",
"securityProvider": "osv",
"cves": ["CVE-2021-23337"],
"cveDetails": [
{
"cve": "CVE-2021-23337",
"severity": "high",
"patchedVersion": "4.17.21"
}
],
"severity": "high",
"vulnerableRange": "<4.17.21",
"patchedVersion": "4.17.21",
"keep": true
}
}
}
}
}
addedDate: ISO timestamp recorded when the entry was first written. Always presentreason: Why the override was needed. Accepts a non-empty string, a ProjectReason, or a BestCaseReasonsource: How the entry was created — "manual" or "security"securityChecked: Whether a security check was performedsecurityCheckDate: When the last security check occurredsecurityCheckResult: Result of the last check — "clean", "error", or "skipped"securityProvider: Which provider detected the vulnerabilitycves: All CVE identifiers related to this vulnerabilitycveDetails: Per-CVE objects with cve, severity, and patchedVersionseverity: Highest severity across all CVEs (low, medium, high, critical)vulnerableRange: Semver range that is affectedpatchedVersion: Version that resolves the vulnerabilitykeep: Prevent --remove-unused from removing this entry. Set to true or a KeepConstraint objectUse a project reason for an engineer-selected pin or patch:
{
"reason": {
"type": "project",
"summary": "Keep the patched fork until upstream publishes a release.",
"pin": "2.4.1",
"patch": "patches/example+2.4.1.patch",
"constraints": ["Requires the current plugin API"],
"references": ["https://example.com/upstream/issue/123"]
}
}
summary is required. pin, patch, constraints, and references are
optional and descriptive; package-manager overrides and appendix patch paths
remain authoritative.
Best-case selection writes a reason tied to the complete portfolio decision:
{
"reason": {
"type": "best-case",
"summary": "Selected as part of the lowest-risk dependency portfolio",
"decisionId": "best-case-4b825dc642cb",
"policyHash": "d14a028c2a3a2bc9",
"search": {
"evaluatedStates": 64,
"provenOptimal": true
},
"impact": {
"fixedVulnerabilities": 3,
"introducedVulnerabilities": 0,
"remainingVulnerabilities": 1
}
},
"cves": ["CVE-2026-1234"]
}
The reason belongs to one dependency item. Dependencies selected by the same
portfolio share a decisionId. CVEs remain in the sibling cves field.
keepTo pin an override so --remove-unused never removes it, set keep: true on the ledger:
{
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"keep": true
}
}
For time-bounded or version-bounded keeps, use a KeepConstraint object:
{
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"keep": {
"reason": "Waiting for upstream patch",
"until": "2027-06-01",
"untilVersion": "4.18.0"
}
}
}
KeepConstraint fields:
reason (required): Why this override is being keptuntil: ISO date after which the keep is considered expireduntilVersion: Semver. The keep expires once the root dependency meets or exceeds this versionreviewBy: Freeform field for tracking who should review the decisionThis allows you to see at a glance which packages were overridden due to security issues and when they were last verified.
depPaths: "workspace" for most monorepos--checkSecurityUse pastoralist.config.cjs for CommonJS or pastoralist.config.mjs for ESM:
export default {
checkSecurity: true,
depPaths: "workspace",
security: {
provider: "osv",
severityThreshold: "high",
},
};
TypeScript config files are not loaded directly. Use JSON, CJS, JS, or MJS config files.
You can use JavaScript config files to provide environment-specific settings:
// pastoralist.config.js
const isDev = process.env.NODE_ENV === "development";
const isCI = process.env.CI === "true";
module.exports = {
checkSecurity: !isDev, // Only check in production/CI
depPaths: "workspace",
security: {
provider: "osv",
severityThreshold: isCI ? "high" : "medium",
autoFix: isCI && !isDev,
},
};
If you're currently using CLI flags, you can migrate to config files:
pastoralist --checkSecurity --depPaths "packages/*/package.json"
{
"checkSecurity": true,
"depPaths": ["packages/*/package.json"]
}
pastoralist
CLI flags still work and will override config file settings.
{
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv"
}
}
{
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv",
"severityThreshold": "medium"
}
}
module.exports = {
depPaths: ["packages/*/package.json", "apps/*/package.json"],
checkSecurity: true,
security: {
provider: "osv",
severityThreshold: "high",
excludePackages: ["@types/*"],
},
};
export default {
checkSecurity: true,
depPaths: "workspace",
security: {
provider: "osv",
severityThreshold: "critical",
},
};
{
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv",
"severityThreshold": "medium"
}
}
{
"pastoralist": {
"security": {
"severityThreshold": "high"
}
}
}
{
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv",
"severityThreshold": "high"
}
}
{
"pastoralist": {
"checkSecurity": true,
"bestCase": {
"enabled": true,
"userOwnedOverrides": ["alpha"],
"riskAggregation": "both",
"objectives": [
"known-exploited",
"critical",
"high",
"expected-exploitation",
"package-exposures",
"compatibility",
"change-count",
"oldness"
],
"search": {
"mode": "auto",
"exactStateLimit": 256,
"beamWidth": 16,
"maxEvaluations": 1000
}
}
}
}
{
"name": "my-project",
"version": "1.0.0",
"pastoralist": {
"checkSecurity": true,
"depPaths": "workspace",
"security": {
"provider": "osv",
"severityThreshold": "medium",
"excludePackages": ["@types/*"]
}
}
}
{
"workspaces": ["packages/*", "apps/*"],
"pastoralist": {
"depPaths": "workspace"
}
}
{
"pastoralist": {
"depPaths": ["packages/*/package.json", "apps/*/package.json"]
}
}
{
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"my-app": "lodash@^4.17.0"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"reason": "Security vulnerability CVE-2021-23337",
"source": "security",
"securityChecked": true,
"securityCheckDate": "2026-05-30T00:00:00.000Z",
"securityCheckResult": "clean",
"securityProvider": "osv",
"cves": ["CVE-2021-23337"],
"cveDetails": [
{
"cve": "CVE-2021-23337",
"severity": "high",
"patchedVersion": "4.17.21"
}
],
"severity": "high",
"vulnerableRange": "<4.17.21",
"patchedVersion": "4.17.21",
"keep": true
}
}
}
}
}
{
"reason": {
"type": "project",
"summary": "Keep the patched fork until upstream publishes a release.",
"pin": "2.4.1",
"patch": "patches/example+2.4.1.patch",
"constraints": ["Requires the current plugin API"],
"references": ["https://example.com/upstream/issue/123"]
}
}
{
"reason": {
"type": "best-case",
"summary": "Selected as part of the lowest-risk dependency portfolio",
"decisionId": "best-case-4b825dc642cb",
"policyHash": "d14a028c2a3a2bc9",
"search": {
"evaluatedStates": 64,
"provenOptimal": true
},
"impact": {
"fixedVulnerabilities": 3,
"introducedVulnerabilities": 0,
"remainingVulnerabilities": 1
}
},
"cves": ["CVE-2026-1234"]
}
{
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"keep": true
}
}
{
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"keep": {
"reason": "Waiting for upstream patch",
"until": "2027-06-01",
"untilVersion": "4.18.0"
}
}
}
export default {
checkSecurity: true,
depPaths: "workspace",
security: {
provider: "osv",
severityThreshold: "high",
},
};
// pastoralist.config.js
const isDev = process.env.NODE_ENV === "development";
const isCI = process.env.CI === "true";
module.exports = {
checkSecurity: !isDev, // Only check in production/CI
depPaths: "workspace",
security: {
provider: "osv",
severityThreshold: isCI ? "high" : "medium",
autoFix: isCI && !isDev,
},
};
pastoralist --checkSecurity --depPaths "packages/*/package.json"
{
"checkSecurity": true,
"depPaths": ["packages/*/package.json"]
}
pastoralist