[ t128n ]

The sand bank, Stanfield, Clarkson, 1836.

Dependency Standback

Patience as a security practice.

The recent LiteLLM PyPI embargo shook the software development community and served as yet another reminder that dependency hygiene isn’t optional.

But not everyone has the ressources to audit every dependency thoroughly. Sometimes the best you can do is just wait. That’s what dependency standback is all about. Before installing or upgrading software, you give it some time to “breathe” in the ecosystem. It doesn’t do anything magical: it simply gives the community time to find problems before they become your problems.

So how long should you wait? A grace period of 7-14 days is a solid default. But it depends on the speed of the ecosystem. An npm package allows for a shorter window than a Julia dependency, because the sheer volume of npm traffic means problems surface faster.

How It Works In Practice

Most modern package managers expose standback natively, with varying degrees of control. The JS ecosystem is the most mature here: npm covers the basics with --min-release-age, pnpm goes further with per-package exclusions via minimumReleaseAgeExclude — useful for whitelisting internal or trusted packages — and bun offers the finest granularity of the three, configuring the age gate down to the second.

On the Python side, uv supports standback out of the box via --exclude-newer. pip originally only accepted absolute dates, but as of version 26.1, it natively supports relative durations via the PnD format1.

The OS and runtime layer is where things get inconsistent. mise handles it well, supporting both relative durations and absolute timestamps. brew and winget, however, don’t support standback at all. Their maintainers argue that existing review cycles make it unnecessary, a position Andrew Nesbitt expands on. I’m not fully convinced. Slip-ups happen, and malicious actors are patient. A review cycle and a grace period don’t have to be mutually exclusive.

Quick Reference

JavaScript

npm

CLI usage
npm install --before 2024-01-01
npm install --min-release-age 4

.npmrc
before = 2024-01-01
min-release-age = 4

pnpm

CLI usage
pnpm install --minimum-release-age 1440

pnpm-workspace.yaml
minimumReleaseAge: 1440
minimumReleaseAgeExclude:
- webpack
- react

For more advanced logic, such as filtering by peerDependency versions, pnpm also exposes standback via .pnpmfile.cjs:

.pnpmfile.cjs
// Example taken from https://pnpm.io/blog/releases/10.16
module.exports = {
finders: {
react17: (ctx) => {
return ctx.readManifest().peerDependencies?.react === "^17.0.0";
},
},
};

bun

CLI usage
bun add @types/bun --minimum-release-age 259200

bunfig.toml
[install]
minimumReleaseAge = 259200
minimumReleaseAgeExcludes = ["@types/node", "typescript"]

taze

CLI usage
pnpm dlx taze --maturity-period 14

taze.config.ts
import { defineConfig } from "taze";
export default defineConfig({
maturityPeriod: 14,
});

Python

uv

CLI usage
uv pip install --exclude-newer 2026-01-01T00:00:00Z litellm
uv add --exclude-newer 2026-01-01T00:00:00Z litellm

pyproject.toml
[tool.uv]
exclude-newer = "2026-01-01T00:00:00Z"

uv.toml
[uv]
exclude-newer = "2026-01-01T00:00:00Z"

pip

As of pip 26.1, the PnD format (where n is the number of days) is supported for relative durations. For older versions or more complex offsets, a shell expression is still required:

CLI usage
# Native relative duration (pip 26.1+)
pip install litellm --uploaded-prior-to P7D
# Absolute timestamp
pip install litellm --uploaded-prior-to 2026-01-01T00:00:00Z
# Shell wrapper (pre-26.1)
pip install litellm --uploaded-prior-to $(date -v-3d "+%Y-%m-%dT%H:%M:%SZ")

.bashrc
# pip 26.1+
export PIP_UPLOADED_PRIOR_TO="P7D"
# pre-26.1
export PIP_UPLOADED_PRIOR_TO=$(date -u -v-3d "+%Y-%m-%dT%H:%M:%SZ")
profile.ps1
$env:PIP_UPLOADED_PRIOR_TO = "P7D"

OS & Runtime

mise

mise.toml
[settings]
install_before = "7d"

brew & winget

Not supported, and not planned.

Footnotes

  1. https://ichard26.github.io/blog/2026/04/whats-new-in-pip-26.1/#dependency-cooldowns