Skip to content

fix(npm): slim cached full packument when minimumDependencyAge is set#35285

Merged
bartlomieju merged 1 commit into
mainfrom
fix/slim-full-packument-cache
Jun 17, 2026
Merged

fix(npm): slim cached full packument when minimumDependencyAge is set#35285
bartlomieju merged 1 commit into
mainfrom
fix/slim-full-packument-cache

Conversation

@bartlomieju

Copy link
Copy Markdown
Member

Setting minimumDependencyAge in deno.json forces Deno to request the
full npm packument instead of the abbreviated install manifest, because
the age check needs each version's publish date (the time field) and
the abbreviated format omits it. The full packument also carries a
complete scripts map for every published version. For packages that
publish very frequently (the reporter hit this with drizzle-orm) that
inflates the cached registry.json to around 100MB, and because that
file is re-read and deserialized on every deno run (not just on
install), parsing it spikes resident memory to roughly 900MB. With the
setting off the same app sits around 80MB. In memory-constrained
environments like a container with a 512MB limit this is enough to
OOM-crash the process on boot.

This slims the full packument down to the abbreviated shape before it is
written to the cache: for each version the scripts map is dropped and
replaced with a hasInstallScript flag derived from the install
lifecycle scripts (preinstall/install/postinstall), while the
time field is kept. That is exactly the representation the registry
returns for the abbreviated format, so the only thing the cache now
retains beyond a normal abbreviated packument is the time field that
minimumDependencyAge actually needs.

The change is safe because it makes a full-format cache behave the same
as an abbreviated-format cache, which is already the default. Resolution
only uses versions, dependencies and dist info, none of which are
touched. The installer reads real lifecycle scripts from the extracted
package's package.json (get_package_extra_info /
fetch_from_package_json), falling back to a registry refetch only for
the deprecated string, a missing bin, or a binding.gyp node-gyp
case, which is identical to how the abbreviated format already works.
has_scripts is computed from either hasInstallScript or the presence
of install scripts in the map, so detection is preserved.

A spec test adds a registry package that has both a publishDate and a
scripts section, installs it with minimumDependencyAge set, and
asserts that the cached registry.json keeps the time field, drops the
per-version scripts map, and records hasInstallScript.

Fixes #35281

When `minimumDependencyAge` is configured, Deno requests the full npm
packument instead of the abbreviated install manifest, because the age
check needs the `time` field (publish dates) that the abbreviated format
omits. The full packument additionally carries a complete `scripts` map
for every version. For frequently published packages (e.g. drizzle-orm)
that bloats the cached `registry.json` to ~100MB, and reparsing it on
every `deno run` spikes RSS to ~900MB.

Slim the full packument down to the abbreviated shape before caching it:
drop each version's `scripts` map, replacing it with a `hasInstallScript`
flag derived from the install lifecycle scripts, while keeping the `time`
field. This matches what the registry returns for the abbreviated format,
so the installer reads the real scripts from the extracted package.json
exactly as it already does for abbreviated packuments.
@bartlomieju
bartlomieju merged commit adb7a2b into main Jun 17, 2026
136 checks passed
@bartlomieju
bartlomieju deleted the fix/slim-full-packument-cache branch June 17, 2026 07:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: deno run uses ~900MB RSS on startup when minimumDependencyAge is enabled

1 participant