Architecture
Deep dive into how Pastoralist works, including overrides, resolutions, patches, and the object anatomy
Deep dive into how Pastoralist works, including overrides, resolutions, patches, and the object anatomy
Pastoralist reads the root package.json, maps each override or resolution into
a pastoralist.appendix entry, and records when the entry was created in its
ledger. Patches created by tools such as patch-package are detected and
tracked on the same entry.
If an override or resolution is no longer needed, Pastoralist marks the appendix
entry as unused and prints a cleanup notice. The override and its appendix entry
are removed only when you run with --remove-unused. Patch files are reported
as potentially unused; Pastoralist does not delete patch files for you.
You manage the override or resolution field; Pastoralist manages the appendix.
In workspace/monorepo setups, Pastoralist:
pastoralist.appendix, with a
ledger entry recording when each override was addeddepPaths or workspaces are configuredStandard single-package project with overrides:
Complex workspace setup with shared overrides:
Overrides allow you to replace a package version in your dependency tree with a different version. This is npm's way of handling dependency conflicts:
{
"overrides": {
"foo": "1.0.0",
"bar": {
"baz": "1.0.0"
}
}
}
Resolutions serve the same purpose for Yarn users, allowing you to force specific versions:
{
"resolutions": {
"foo": "1.0.0",
"**/bar/baz": "1.0.0"
}
}
Patches are custom modifications to node_modules packages, typically created with tools like patch-package. Pastoralist automatically detects and tracks these patches.
The Pastoralist object in your package.json provides full transparency into what's being managed:
{
"overrides": {
"minimist": "1.2.8"
},
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"my-app": "minimist@^1.2.6",
"mkdirp": "minimist@^1.2.5"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"reason": "Pin minimist while upstream packages adopt the patched version.",
"source": "manual"
}
}
}
}
}
[email protected]addedDate, optional reason and source, security metadata (securityProvider,
cves, cveDetails, severity, vulnerableRange, patchedVersion), and
optional keep constraintsHow nested overrides work for transitive dependencies:
Pastoralist uses sync file I/O intentionally. As a CLI tool, predictable execution and simple debugging outweigh async benefits.
Two caches avoid redundant work: jsonCache (parsed package.json files) and dependencyTreeCache (npm ls output). Caches persist across update() calls - pass clearCache: true to reset.
npm registry requests are limited to 5 concurrent to avoid rate limits during security scans.
Complete flow of how dependencies are resolved with overrides:
{
"overrides": {
"foo": "1.0.0",
"bar": {
"baz": "1.0.0"
}
}
}
{
"resolutions": {
"foo": "1.0.0",
"**/bar/baz": "1.0.0"
}
}
{
"overrides": {
"minimist": "1.2.8"
},
"pastoralist": {
"appendix": {
"[email protected]": {
"dependents": {
"my-app": "minimist@^1.2.6",
"mkdirp": "minimist@^1.2.5"
},
"ledger": {
"addedDate": "2026-05-30T00:00:00.000Z",
"reason": "Pin minimist while upstream packages adopt the patched version.",
"source": "manual"
}
}
}
}
}