npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@webpro/pnpm-exclude-newer

v1.0.0

Published

Resolve a pnpm lockfile whose entire dependency tree (direct + transitive) excludes versions published after a cutoff — a transitive minimumReleaseAge / uv-style --exclude-newer for pnpm.

Readme

pnpm-exclude-newer

NOTE: This script is 100% generated. Use at your own risk.

Bring a pnpm project up to the latest versions that are old enough to trust: every dependency — direct and transitive — capped to what was published before a cutoff. Think uv's --exclude-newer, or a transitive minimumReleaseAge, for pnpm.

By default it rewrites each direct dep range in package.json to the latest mature version (keeping its ^/~ operator) and resolves a fully age-capped lockfile. Pass --no-bump to leave package.json alone and only resolve the lockfile within the existing ranges.

pnpm dlx @webpro/pnpm-exclude-newer            # cutoff from pnpm-workspace.yaml's minimumReleaseAge (else 1 day)
pnpm dlx @webpro/pnpm-exclude-newer --age 4320 # 3 days
pnpm dlx @webpro/pnpm-exclude-newer --exclude-newer 2026-05-30
pnpm dlx @webpro/pnpm-exclude-newer --no-bump  # lockfile only, don't touch package.json

Why this exists

pnpm's minimumReleaseAge is verify-only: the resolver picks the latest in-range version and then rejects it if it's too fresh (ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION / ERR_PNPM_NO_MATURE_MATCHING_VERSION) — it does not fall back to the latest mature version. resolutionMode: time-based is meant to do age-aware resolution but is broken when combined with minimumReleaseAge. So out of the box you can't get a lockfile that's mature all the way down, and the escape hatches are all exclusion-based.

Related pnpm issues: #10257 (time-based ignored), #11068 (transitive deps error out), #11203 (no intermediate fallback), #10488 (excludes don't cascade).

How it compares

Cooldown / min-release-age features that work at the manifest or PR layer only gate direct dependencies — your package manager still resolves the transitive tree to the freshest versions at install time:

| Tool | Operates on | Direct | Transitive | | -------------------------------------------------- | ----------------------- | :------------------: | :---------: | | npm-check-updates --cooldown | rewrites package.json | ✅ | ❌ | | Renovate minimumReleaseAge / Dependabot cooldown | opens PRs | ✅ | ❌ | | pnpm minimumReleaseAge | resolve + verify | ⚠️ latest-tag only | ❌ (errors) | | pnpm-exclude-newer | registry resolution | ✅ | ✅ |

Verified: ncu --cooldown 3 on a project with a single direct dependency correctly cools that dependency, yet its lockfile still contained a transitive dependency published 2 days earlier. pnpm-exclude-newer on the same project left zero entries younger than the cutoff. Only resolution-level filtering reaches transitive dependencies.

How it works

  1. Stands up a throwaway local registry mirror that hides every version published on/after the cutoff (and repoints dist-tags.latest to the newest mature version).
  2. Unless --no-bump, rewrites each direct dep range in your package.json(s) to that latest mature version — preserving the ^/~ operator. This both updates stale ranges and lowers any whose floor is too fresh to have a mature match (e.g. ^1.69.0^1.68.0), which would otherwise error. Non-registry specs (workspace:, catalog:, file:, git, URL, npm: aliases, *, complex ranges) are left untouched.
  3. Copies the manifests into a clean temp tree (your node_modules would otherwise leak fresh peer versions) and runs pnpm install --lockfile-only against the mirror — so pnpm's normal resolver produces a transitively age-capped tree.
  4. Copies the lockfile back and runs a real pnpm install, letting pnpm's own gate verify it.

Real integrity hashes and tarballs come straight from the upstream registry, so the lockfile stays portable. If resolution fails, any package.json bumps from this run are reverted.

Options

| flag | meaning | | ------------------------ | --------------------------------------------------------------------------------------------- | | --exclude-newer <date> | hide versions published on/after <date> (e.g. 2026-05-30) | | --age <minutes> | cutoff = now − minutes (default: minimumReleaseAge from pnpm-workspace.yaml, else 1440) | | --no-bump | don't rewrite package.json; only resolve the lockfile within the existing ranges | | --no-install | stop after writing the lockfile (skip the verifying install) | | -h, --help | usage |

If a resolution fails, it means an already-mature package depends on a still-too-fresh version — wait for it to age, or raise the cutoff for that run.

Requirements & limitations

  • Node ≥ 18 (global fetch) and pnpm on PATH.
  • pnpm version: resolves with whatever pnpm is on PATH (under corepack, the repo's packageManager pin — recommended for fidelity). A mismatch can change resolution; e.g. pnpm 11 ignores the pnpm field in package.json, so on an older repo that keeps overrides/patchedDependencies there, run it under the matching pnpm.
  • Registries: only the default registry is mirrored (read with its _authToken from npm config / .npmrc). Per-scope registries (@scope:registry=) bypass the mirror — those scopes aren't age-filtered (and private ones may fail).
  • Config fidelity: the isolated install copies package.json(s), pnpm-workspace.yaml, .pnpmfile.cjs/pnpmfile.cjs, and patches/. Resolution-affecting .npmrc settings (e.g. auto-install-peers, node-linker) are not applied — keep them in pnpm-workspace.yaml.
  • shared-workspace-lockfile=false (per-package lockfiles) isn't supported.
  • Non-registry deps (git, tarball URL, file:, link:, workspace:) have no published-version concept and aren't age-filtered — they resolve as usual.
  • If an overrides / catalog / patchedDependencies entry pins an exact version newer than the cutoff, resolution fails (the mirror hides it) — age the pin or raise the cutoff.
  • minimumReleaseAgeExclude is not honored: everything is aged, no exceptions.
  • Versions the registry has no publish time for are treated as too-new (excluded).

License

MIT