How to Set a Minimum Package Age in npm, pnpm, Yarn, Bun, uv and pip (2026)
Set a minimum package age in npm, pnpm, Yarn, Bun, uv and pip in 2026: the exact setting, its unit, the first version that shipped it, and how to exempt.

Turn it on in every project, because each tool takes one line of config or one flag. On pnpm 11 a one-day gate is already on by default, since minimumReleaseAge is 1440 minutes. npm takes min-release-age=7, counted in days. Yarn, Bun, uv and pip take a setting too, and each one lives in the tool's own config, so there is no extra product to buy. The cost is delay: a fix you need today waits until its age passes, unless you exempt that package by name.
Cyberpresso data: As of 4 November 2026, our archive holds 256 news posts dated 18 August to 4 November 2026. Eight of them report malicious code published to npm, PyPI, crates.io or Packagist: the Rust crates arrayref, internment and append-only-vec on crates.io (22 August), the Trinitite npm worm (1 September), the Packagist themes (2 September), a malicious PyPI package that Anthropic's Mythos 5 model published during testing and 15 third-party systems installed (11 September), the poisoned TanStack npm packages behind the CrowdSec breach (22 September), LiteLLM 1.107.0 on PyPI (23 October), the npm package function-color that a planted AGENTS.md file told a coding agent to install (27 October) and the testmetest npm packages (28 October). These are our post dates. How the count was made is in the method section at the end.
A release-age gate targets the pattern in those posts: a bad version is published, automation installs it within minutes, and the registry pulls it hours later. The table gives the exact setting for each tool.
| Tool | Setting and default | Where | Unit | Since version |
|---|---|---|---|---|
| pnpm | minimumReleaseAge, default 1440 on pnpm 11 | pnpm-workspace.yaml | minutes | v10.16.0, 12 September 2025; default in v11.0.0, 28 April 2026 |
| npm | min-release-age, example 7 | npm config, such as .npmrc | days | CLI 11.10.0, 11 February 2026 |
| Yarn Berry | npmMinimalAgeGate, default 1d since 4.15.0, docs example "1w" | .yarnrc.yml | a duration string | 4.10.0, 18 September 2025 |
| Bun | minimumReleaseAge, example 259200 | bunfig.toml, under [install] | seconds, or a unit such as 3d | Bun 1.3.0, 10 October 2025 |
| uv | exclude-newer, example "1 week" | uv.toml, or [tool.uv] in pyproject.toml | a timestamp, or a duration such as 1 week or P7D | relative durations in 0.9.17, 9 December 2025 |
| pip | --uploaded-prior-to, example P3D | the command line, or PIP_UPLOADED_PRIOR_TO | an ISO 8601 datetime, or whole days as P<n>D | pip 26.0, 30 January 2026; the day form in 26.1, 26 April 2026 |
| Renovate | minimumReleaseAge, example "14 days" | Renovate config | days, or a unit such as "14 days" | no version on the docs page |
| Dependabot | cooldown with default-days | dependabot.yml | days, from 1 to 90 | default of 3 days from 14 July 2026 |
Units are the trap. pnpm counts minutes, npm counts days, and Bun counts seconds unless you add a unit. Copy npm's 7 into pnpm and the gate is seven minutes, not seven days. Check the unit in the table before you copy a number between files.
How do you set it in pnpm and npm?
pnpm's settings page prints Default: 1440 for minimumReleaseAge, measured in minutes. The pnpm 11.0.0 release, published 28 April 2026, made 1440 the default, which is one day, and set minimumReleaseAgeStrict to false. So on pnpm 11 a one-day gate is on before you write any config.
Strict decides what happens when the gate leaves no version old enough. With strict false, pnpm falls back to a version that does not meet the gate, so a version younger than a day can be installed with no error. With strict true, resolution fails instead. The docs say strict defaults to true only when you set minimumReleaseAge yourself, so the pnpm 11 default is the lenient one. The example below sets the value explicitly, which turns strict on.
minimumReleaseAge: 1440
minimumReleaseAgeExclude:
- webpack
- react
The exemption list takes package names, patterns such as '@myorg/*', and exact versions such as [email protected]. With strict on, a version younger than the gate is not installed quietly; exempted packages and, by default, versions whose registry metadata has no publish time (minimumReleaseAgeIgnoreMissingTime) still pass. Strict is also the setting that turns a Monday morning install into an error, so tell the team before you switch it on.
npm calls the setting min-release-age, in days. Its config page says only versions available more than that many days ago are installed. The option arrived in CLI 11.10.0 on 11 February 2026, and the exemption list min-release-age-exclude came in 11.17.0 on 11 June 2026. The older before option takes a calendar date for the same cut, and the exemption list applies to it too.
min-release-age=7
min-release-age-exclude[]=@myorg/*
min-release-age-exclude[]=my-internal-pkg
How about Yarn, Bun, uv and pip?
Yarn Berry's configuration page names the setting npmMinimalAgeGate. It takes a duration string, the docs example is "1w", and the page prints no default. Yarn's 4.15.0 release notes say 1d became the default, so set your own value. The setting arrived in 4.10.0 on 18 September 2025. Exemptions go in npmPreapprovedPackages, a list of descriptors or glob patterns that sit outside all package gates.
npmMinimalAgeGate: "1w"
Bun's docs use minimumReleaseAge under [install] in bunfig.toml, in seconds, so 259200 is the docs example. Units such as 3d also work (install docs). The setting came in with commit f7da0ac, dated 6 October 2025, which is included in Bun 1.3.0, released 10 October 2025. The exemption list minimumReleaseAgeExcludes works two ways: a bare name exempts every version, and a name with exact versions exempts only those. Ranges such as ^5 are ignored with a warning.
[install]
minimumReleaseAge = 259200
minimumReleaseAgeExcludes = ["@types/node", "[email protected]"]
uv's settings reference takes exclude-newer as an RFC 3339 timestamp, a friendly duration such as 1 week, or an ISO 8601 duration such as P7D. Calendar units are not allowed, and durations use 24-hour days. Relative values arrived in uv 0.9.17 on 9 December 2025. The docs show the keys under [tool.uv] in pyproject.toml, or with the same keys and no table header in uv.toml:
[tool.uv]
exclude-newer = "1 week"
exclude-newer-package = { my-internal-pkg = false }
The per-package key takes the same values, and false exempts that package from the global limit.
pip's install docs describe --uploaded-prior-to, which takes an ISO 8601 datetime, read in local time when no zone is given, or a whole number of days written P<n>D. The option is in pip 26.0 from 30 January 2026, and the day form is in 26.1 from 26 April 2026, in the same changelog. The docs say the option only works with indexes that provide upload-time metadata, and the page documents one global cut-off with no per-package exemption.
pip install --uploaded-prior-to P3D -r requirements.txt
What about Renovate and Dependabot?
In Renovate, the docs take minimumReleaseAge as a value such as 14 days, and say a dependency update is not suggested until that many days after release. The docs page prints no version. Its integration list names npm, where Renovate passes --before, and Poetry, and it names no link to the pnpm, Yarn, uv, pdm or mise settings.
To exempt a package from Renovate's check, add a package rule that sets the value to null. The docs example, verbatim:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
// for instance
"security:minimumReleaseAgeNpm",
],
"packageRules": [
{
"description": "Disable minimum release age checks for internal dependencies",
"matchPackageNames": ["@super-secret-organisation/*"],
"minimumReleaseAge": null,
},
],
}
Dependabot uses a cooldown block in dependabot.yml. GitHub's guide to optimizing version-update pull requests says the cooldown runs from 1 to 90 days, and include and exclude take up to 150 entries each. The docs example, verbatim:
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
cooldown:
default-days: 5
semver-major-days: 30
semver-minor-days: 7
semver-patch-days: 3
include:
- "requests"
- "numpy"
- "pandas*"
- "django"
exclude:
- "pandas"
Dependabot applies a default cooldown to version updates even when no cooldown block is set, as GitHub's changelog of 14 July 2026 also says. The cooldown covers version updates only, not security updates.
How do you exempt your own packages?
Every exemption is a hole you chose on purpose, so keep the list short and dated. The table shows what each exemption matches.
| Tool | Exemption setting | What it matches |
|---|---|---|
| pnpm | minimumReleaseAgeExclude | Package names, patterns such as @myorg/*, or exact versions joined with || |
| npm | min-release-age-exclude[] | Package names or minimatch globs, and it also exempts from before |
| Yarn Berry | npmPreapprovedPackages | Package descriptors or glob patterns, exempt from all package gates |
| Bun | minimumReleaseAgeExcludes | A name exempts every version; a name with exact versions exempts only those |
| uv | exclude-newer-package set to false | One named package, taken out of the global limit |
| Renovate | A package rule with minimumReleaseAge set to null | Package names matched by matchPackageNames, such as @super-secret-organisation/* |
| Dependabot | cooldown include and exclude | Up to 150 entries each, with wildcards |
| pip | None on the docs page | One global cut-off for the whole install |
What the gate does not do
The gate delays security fixes as much as attacks. A patched release waits too, unless it is on the exemption list, so each entry needs an owner and a date.
It does not stop a maintainer who stays malicious for weeks. A version that survives past the window installs like any other, so the gate buys time for other people to notice a problem. It is not a verdict on the package.
It does nothing for versions already on disk. Bun's docs say the filter only affects new package resolution, and entries already in bun.lock stay as they are. A poisoned version that reached a lockfile last month stays there after you turn the setting on. Cleaning up what already landed is a separate job, and the steps are in how to get secrets off developer laptops. Rotating any credential it could have read is also separate, and the secrets management comparison covers the tools for that. A stolen token also outlives the gate, as the CrowdSec case shows, where hackers reused a token.
Pinning freezes what you have, and the gate limits what you add, so use both. Routes that start with a job interview need their own checks, covered in the fake job interview malware playbook. The November 2026 security checklist puts the controls side by side.
Which control to use when a tool has no age setting
Where a tool has no age rule, the nearest control is a lockfile that CI refuses to change. These flags are from each tool's docs, read on 4 November 2026. A lockfile freezes versions, so it does not check their age. It only stops drift after a reviewed install.
- npm:
npm cineeds an existingpackage-lock.jsonornpm-shrinkwrap.json. It never writes to the lockfile and exits with an error whenpackage.jsonand the lock disagree. - pnpm:
pnpm install --frozen-lockfilefails when the lockfile is out of sync with the manifest. pnpm sets it to true by default in CI when a lockfile is present. - Yarn Berry:
yarn install --immutableaborts with an error if the lockfile would be modified, and the docs say it defaults to true on CI. - Bun:
bun install --frozen-lockfileinstalls the exact versions in the lockfile and exits with an error whenpackage.jsonandbun.lockdisagree. Bun does not turn it on in CI automatically, so pass the flag or usebun ci. - uv:
uv sync --lockedasserts thatuv.lockstays unchanged. The flag's source text says it requires an up-to-date lockfile and exits with an error when the lockfile is missing or needs an update. - pip:
pip install --require-hashesrequires a hash for each requirement, for repeatable installs. It is implied when any requirement carries a--hashoption.
How an age gate would have treated the LiteLLM release
LiteLLM's incident post lists seven PyPI uploads of litellm==1.107.0 between 11:39:51 and 11:40:13 UTC on 21 October 2026, and says PyPI had removed the version by 13:23 UTC. The post describes the window as about two hours. Its own clock times run to less than two hours, from 11:39 to 13:23 UTC. The release is covered in our LiteLLM post.
Plain arithmetic: a one-day gate in pip or uv would have kept 1.107.0 out of resolution until about 11:39 UTC on 22 October, about 22 hours after PyPI removed it. Any longer gate covers the same window. The LiteLLM post also names Docker Hub and GHCR tags, and a Python gate does not reach a container pull, so those tags need their own control.
The testmetest case is different: our news post on the testmetest npm worm describes payloads in 42 GitHub repositories, which a registry gate never sees.
Pick a value and check it
On pnpm 11, 1440 minutes is already the default, so it is a sensible floor. Longer windows delay fixes more, and each exemption shrinks the protection. Write each value in the tool's own unit.
Test the setting once in CI with a version younger than the window. With strict true the install fails; with strict false, as on pnpm 11 by default, it may quietly pick that young version. Keep exemptions in version control with a note and a date, and remove each one when the release is old enough.
FAQ
What is the setting for a minimum package age in npm?
It is min-release-age, in days, in npm's config, for example .npmrc. The line min-release-age=7 keeps versions published less than seven days ago out of the install. npm added the setting in CLI 11.10.0 on 11 February 2026, and the exemption list min-release-age-exclude came in 11.17.0 on 11 June 2026.
Does a minimum package age cost anything?
Each tool takes the setting in its own config, so there is no extra product to buy. The cost is delay and exemptions. Dependabot's default cooldown covers version updates only, not security updates.
Would an age gate have stopped LiteLLM 1.107.0?
For PyPI installs, yes. The upload at 11:39 UTC on 21 October would stay out of pip or uv resolution until about 11:39 UTC on 22 October, after PyPI removed it by 13:23 UTC on 21 October. Docker tags are a different route, and a Python gate does not cover them.
Does a minimum package age protect versions I already installed?
No. Bun's docs say the filter only affects new resolution, and entries already in bun.lock stay as they are. A gate stops the next install from picking a young version. It does nothing about the one already in your lockfile, which needs its own review.
Can I exempt my own packages from the age gate?
Yes, in seven of the eight tools in the table; pip is the exception. pnpm uses minimumReleaseAgeExclude, npm uses min-release-age-exclude[], Yarn uses npmPreapprovedPackages, Bun uses minimumReleaseAgeExcludes, and uv takes exclude-newer-package set to false. Renovate and Dependabot have their own rules. The pip page documents only one global cut-off, so pip has no per-package exemption on that page.
Does a lockfile replace an age gate?
No. A lockfile freezes versions and does not check how old they are. npm ci, pnpm install --frozen-lockfile and uv sync --locked stop drift after a reviewed install, while the age gate limits what enters the lockfile in the first place. Use both.
Which value should a team start with?
Start with the defaults you already have. pnpm 11 ships with its gate already on, and Dependabot's default cooldown is the value its docs state. Longer windows delay fixes more, and every exemption shrinks the protection, so keep the exemption list short and dated.
How we checked this page
Each setting was checked on 4 November 2026 against the tool's own docs, and where a docs page printed no version, against its changelog or release notes. An introducing version is the first release that shipped the setting. The LiteLLM window comes from LiteLLM's post of 21 October 2026.
How the count was made. As of 4 November 2026, our archive holds 256 news posts with no type: key, dated 18 August to 4 November 2026. An incident here is malicious code published to npm, PyPI, crates.io or Packagist, where that release is part of the incident the post reports. Eight posts meet that test, and the dates above are our post dates. One more post names the @antv npm packages only as an overlap in attacker infrastructure, so it is not counted. Left out: editor extension registries (GlassWorm on Open VSX and the Cursor marketplace copy), which hold extensions rather than code libraries and are covered in how to find malicious editor extensions, and a RubyGems upload claim that OpenAI says it has not verified.
Louis Corneloup, founder of Toolradar and Dupple, is the author. How products are described is on how we rate, and corrections sit in the editorial policy.
Cite this: Cyberpresso, "How to Set a Minimum Package Age in npm, pnpm, Yarn, Bun, uv and pip (2026)", November 2026.
For the daily supply chain incidents behind these settings, the Cyberpresso newsletter is the short brief.
Some offers on this page may be paid placements or contain affiliate links.
Cyberpresso: daily cyber & AI brief
Free daily newsletter, read in 5 minutes.
Subscribe free