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

@crbroughton/recul

v0.6.0

Published

Stay N versions behind the latest published release of your npm dependencies to avoid supply chain attacks.

Downloads

898

Readme

recul

Stay N versions behind the latest published release of your npm dependencies to avoid supply chain attacks.

recul is not a replacement for typical auditing via npm audit or third party security tools; it is a complementary layer that reduces the attack surface without requiring active effort on every release cycle.

How it works

Given a lag of N, the target version is versions[latest_index - N]. Only stable releases are counted; pre-release versions (configurable, defaults to -alpha, -beta, -rc, -next, -canary, -dev) are excluded. If a package has fewer releases than the lag value, recul pins to the oldest available stable version.

Packages already older than the lag target are left alone by default. The invariant is "never be too new", not "be exactly N behind".

Requirements

  • Node.js 18 or later

Installation

npm i -D @crbroughton/recul
# or
pnpm add -D @crbroughton/recul

Quick start

# Create a config file in the current directory
recul init

# Audit your dependencies
recul

Configuration

Commit a recul.config.jsonc to standardise settings across the team.

{
  // How many versions to stay behind the latest published release.
  // Counted in releases, not semver increments.
  //
  //   1  →  days to weeks   (fast-moving projects, minimal buffer)
  //   2  →  weeks           (balanced default, recommended)
  //   3  →  weeks to months (cautious teams, slower release cadences)
  //   5+ →  months          (regulated environments, high-security contexts)
  "lag": 2,

  // Package manager: "npm" | "pnpm"
  "packageManager": "pnpm",

  // Path to the package.json to audit, relative to this config file.
  "packageFile": "package.json",

  // How to handle packages already older than the lag target.
  //   "ignore"  →  treat as ok, no output (default)
  //   "report"  →  surface them with a safe upgrade-to-target command
  "behindBehavior": "ignore",

  // Version prefix used in generated install commands.
  //   "exact"  →  1.3.4    (recommended; audits are reliable)
  //   "caret"  →  ^1.3.4   (allows minor/patch drift)
  //   "tilde"  →  ~1.3.4   (allows patch drift only)
  //
  // Per-package map also supported:
  //   { "default": "exact", "react": "tilde" }
  "rangeSpecifier": "exact",

  // Packages to skip entirely.
  "ignore": [],

  // Minimum days a version must have been published before it is eligible
  // as a lag target. Combines with "lag" for defence-in-depth.
  // Omit or set to 0 to disable.
  "minimumReleaseAge": 3,

  // Version strings containing any of these substrings are treated as
  // pre-releases and excluded from the candidate list.
  "preReleaseFilter": ["-alpha", "-beta", "-rc", "-next", "-canary", "-dev"],

  // Restrict the candidate list to the same major as the currently declared version.
  // Prevents resolving a target across major version lines (e.g. axios 0.x vs 1.x).
  // Can be a per-package map: { "default": true, "axios": false }
  "sameMajor": true
}

A config file is required; run recul init if you do not have one.

CLI flags

| Flag | Description | |------|-------------| | -f, --file | Path to package.json (default: package.json) | | --fix | Apply catalog fixes directly to pnpm-workspace.yaml | | --behindBehavior=<value> | Override behindBehavior from config (ignore or report) |

Output

recul  staying 2 versions behind latest

settings
setting    value   description
──────────────────────────────────────────────────────────────────
lag        2       stay 2 versions behind latest
pm         pnpm    the chosen package manager
behind     ignore  ignore packages behind target
range      exact   pin exact versions
minAge     3       skip versions published within the last 3 days
sameMajor  true    restrict candidates to current major

package    declared  → target  installed  latest  gap  status
────────────────────────────────────────────────────────────────
express    ^4.19.2   4.17.3    4.17.3     4.19.2  2    ↓ will pin back
react      ^18.3.1   18.1.0    18.0.0     18.3.1  2    ↓ will pin back
typescript 5.4.5     5.4.5     5.4.5      5.4.5   0    ✓ ok

to pin back:
  pnpm add [email protected] [email protected]

Status values

| Status | Meaning | |--------|---------| | ✓ ok | At or behind the lag target | | ↓ will pin back | Ahead of the lag target; install command shown | | ↑ safe to upgrade | Behind the target (only shown when behindBehavior: report) | | ✗ unresolved | Registry fetch failed or no stable versions found |

A ⚠ declared <specifier> warning is appended when a package is declared with a different range prefix than rangeSpecifier; this means the audited version may differ from what is actually installed.

pnpm monorepo support

In a pnpm workspace, recul detects pnpm-workspace.yaml and audits each package separately, grouping output by package:

─── packages/app ────────────────────────────────────────────────
package    declared  → target  installed  latest  gap  status
─────────────────────────────────────────────────────────────────
express    5.2.1     5.0.0     5.2.1      5.2.1   0    ↓ will pin back

─── packages/lib ────────────────────────────────────────────────
package    declared  → target  installed  latest  gap  status
─────────────────────────────────────────────────────────────────
lodash     4.18.1    4.17.23   4.18.1     4.18.1  0    ↓ will pin back

Column widths are computed once across all packages so the table stays aligned. Catalog violations from all packages are collected and shown together at the end. Pass --fix to apply all catalog updates in one go.

pnpm catalog support

When using pnpm workspaces with a catalogs block in pnpm-workspace.yaml, recul reads catalog entries to resolve catalog: and catalog:<name> references in package.json.

Violations in catalog-managed packages are reported with the catalog entry to update rather than an install command. Pass --fix to apply the updates directly to pnpm-workspace.yaml.

Lockfile support

When a lockfile is present, recul reads the installed version from it and uses that for comparison rather than the declared range. This gives accurate results for packages declared with ^ or ~.

| Package manager | Lockfile | |----------------|----------| | npm | package-lock.json (v3) | | pnpm | pnpm-lock.yaml (v6+) |

GitHub Actions

Add recul to your CI pipeline to fail the workflow when dependencies are ahead of their lag target:

- uses: actions/checkout@v4
- uses: actions/setup-node@v4
  with:
    node-version: 20
- uses: CRBroughton/recul@v1

Inputs

| Input | Default | Description | |-------|---------|-------------| | working-directory | . | Directory containing recul.config.jsonc and package.json | | fail-on-violations | true | Set to false for informational runs that never fail | | behind-behavior | `` | Override behindBehavior from config (ignore or report) |

Job summary

recul writes a markdown table to the GitHub Actions job summary automatically. In monorepo mode each workspace package gets its own section. No configuration required.

Exit codes

| Code | Meaning | |------|---------| | 0 | All packages are within their lag target | | 1 | One or more packages need pinning, are unresolved, or (when behindBehavior: report) are behind target |